gsk: Move Vulkan sources to a subdirectory
authorMatthias Clasen <mclasen@redhat.com>
Sat, 6 Jan 2018 14:36:55 +0000 (09:36 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 6 Jan 2018 14:36:55 +0000 (09:36 -0500)
Following what was already done for GL.

94 files changed:
gsk/gskrenderer.c
gsk/gskvulkanblendmodepipeline.c [deleted file]
gsk/gskvulkanblendmodepipelineprivate.h [deleted file]
gsk/gskvulkanblurpipeline.c [deleted file]
gsk/gskvulkanblurpipelineprivate.h [deleted file]
gsk/gskvulkanborderpipeline.c [deleted file]
gsk/gskvulkanborderpipelineprivate.h [deleted file]
gsk/gskvulkanboxshadowpipeline.c [deleted file]
gsk/gskvulkanboxshadowpipelineprivate.h [deleted file]
gsk/gskvulkanbuffer.c [deleted file]
gsk/gskvulkanbufferprivate.h [deleted file]
gsk/gskvulkanclip.c [deleted file]
gsk/gskvulkanclipprivate.h [deleted file]
gsk/gskvulkancolorpipeline.c [deleted file]
gsk/gskvulkancolorpipelineprivate.h [deleted file]
gsk/gskvulkancolortextpipeline.c [deleted file]
gsk/gskvulkancolortextpipelineprivate.h [deleted file]
gsk/gskvulkancommandpool.c [deleted file]
gsk/gskvulkancommandpoolprivate.h [deleted file]
gsk/gskvulkancrossfadepipeline.c [deleted file]
gsk/gskvulkancrossfadepipelineprivate.h [deleted file]
gsk/gskvulkaneffectpipeline.c [deleted file]
gsk/gskvulkaneffectpipelineprivate.h [deleted file]
gsk/gskvulkanglyphcache.c [deleted file]
gsk/gskvulkanglyphcacheprivate.h [deleted file]
gsk/gskvulkanimage.c [deleted file]
gsk/gskvulkanimageprivate.h [deleted file]
gsk/gskvulkanlineargradientpipeline.c [deleted file]
gsk/gskvulkanlineargradientpipelineprivate.h [deleted file]
gsk/gskvulkanmemory.c [deleted file]
gsk/gskvulkanmemoryprivate.h [deleted file]
gsk/gskvulkanpipeline.c [deleted file]
gsk/gskvulkanpipelineprivate.h [deleted file]
gsk/gskvulkanpushconstants.c [deleted file]
gsk/gskvulkanpushconstantsprivate.h [deleted file]
gsk/gskvulkanrender.c [deleted file]
gsk/gskvulkanrenderer.c [deleted file]
gsk/gskvulkanrendererprivate.h [deleted file]
gsk/gskvulkanrenderpass.c [deleted file]
gsk/gskvulkanrenderpassprivate.h [deleted file]
gsk/gskvulkanrenderprivate.h [deleted file]
gsk/gskvulkanshader.c [deleted file]
gsk/gskvulkanshaderprivate.h [deleted file]
gsk/gskvulkantextpipeline.c [deleted file]
gsk/gskvulkantextpipelineprivate.h [deleted file]
gsk/gskvulkantexturepipeline.c [deleted file]
gsk/gskvulkantexturepipelineprivate.h [deleted file]
gsk/meson.build
gsk/vulkan/gskvulkanblendmodepipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanblendmodepipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanblurpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanblurpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanborderpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanborderpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanboxshadowpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanboxshadowpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanbuffer.c [new file with mode: 0644]
gsk/vulkan/gskvulkanbufferprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanclip.c [new file with mode: 0644]
gsk/vulkan/gskvulkanclipprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkancolorpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkancolorpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkancolortextpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkancolortextpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkancommandpool.c [new file with mode: 0644]
gsk/vulkan/gskvulkancommandpoolprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkancrossfadepipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkancrossfadepipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkaneffectpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkaneffectpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanglyphcache.c [new file with mode: 0644]
gsk/vulkan/gskvulkanglyphcacheprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanimage.c [new file with mode: 0644]
gsk/vulkan/gskvulkanimageprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanlineargradientpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanlineargradientpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanmemory.c [new file with mode: 0644]
gsk/vulkan/gskvulkanmemoryprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkanpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanpushconstants.c [new file with mode: 0644]
gsk/vulkan/gskvulkanpushconstantsprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanrender.c [new file with mode: 0644]
gsk/vulkan/gskvulkanrenderer.c [new file with mode: 0644]
gsk/vulkan/gskvulkanrendererprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanrenderpass.c [new file with mode: 0644]
gsk/vulkan/gskvulkanrenderpassprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanrenderprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanshader.c [new file with mode: 0644]
gsk/vulkan/gskvulkanshaderprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkantextpipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkantextpipelineprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkantexturepipeline.c [new file with mode: 0644]
gsk/vulkan/gskvulkantexturepipelineprivate.h [new file with mode: 0644]

index 9bdfd6a26a25d8977eefd160ca4cab2bdf226fa3..0e661792fcefa46b5d892fcc27b07bc55a4ea810 100644 (file)
@@ -59,7 +59,7 @@
 #include "gskbroadwayrendererprivate.h"
 #endif
 #ifdef GDK_RENDERING_VULKAN
-#include "gskvulkanrendererprivate.h"
+#include "vulkan/gskvulkanrendererprivate.h"
 #endif
 
 typedef struct
diff --git a/gsk/gskvulkanblendmodepipeline.c b/gsk/gskvulkanblendmodepipeline.c
deleted file mode 100644 (file)
index 117ed41..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanblendmodepipelineprivate.h"
-
-struct _GskVulkanBlendModePipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
-
-struct _GskVulkanBlendModeInstance
-{
-  float rect[4];
-  float start_tex_rect[4];
-  float end_tex_rect[4];
-  guint32 blend_mode;
-};
-
-G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanBlendModeInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32_UINT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanBlendModePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_blend_mode_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_class_init (GskVulkanBlendModePipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blend_mode_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_blend_mode_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_init (GskVulkanBlendModePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext        *context,
-                                    VkPipelineLayout         layout,
-                                    const char              *shader_name,
-                                    VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline)
-{
-  return sizeof (GskVulkanBlendModeInstance);
-}
-
-void
-gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
-                                                    guchar                *data,
-                                                    const graphene_rect_t *bounds,
-                                                    const graphene_rect_t *start_tex_rect,
-                                                    const graphene_rect_t *end_tex_rect,
-                                                    GskBlendMode blend_mode)
-{
-  GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data;
-
-  instance->rect[0] = bounds->origin.x;
-  instance->rect[1] = bounds->origin.y;
-  instance->rect[2] = bounds->size.width;
-  instance->rect[3] = bounds->size.height;
-
-  instance->start_tex_rect[0] = start_tex_rect->origin.x;
-  instance->start_tex_rect[1] = start_tex_rect->origin.y;
-  instance->start_tex_rect[2] = start_tex_rect->size.width;
-  instance->start_tex_rect[3] = start_tex_rect->size.height;
-
-  instance->end_tex_rect[0] = end_tex_rect->origin.x;
-  instance->end_tex_rect[1] = end_tex_rect->origin.y;
-  instance->end_tex_rect[2] = end_tex_rect->size.width;
-  instance->end_tex_rect[3] = end_tex_rect->size.height;
-
-  instance->blend_mode = blend_mode;
-}
-
-gsize
-gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
-                                     VkCommandBuffer        command_buffer,
-                                     gsize                  offset,
-                                     gsize                  n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkanblendmodepipelineprivate.h b/gsk/gskvulkanblendmodepipelineprivate.h
deleted file mode 100644 (file)
index 67822e4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskenums.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBlendModePipelineLayout GskVulkanBlendModePipelineLayout;
-
-#define GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE (gsk_vulkan_blend_mode_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK, VULKAN_BLEND_MODE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new                 (GdkVulkanContext           *context,
-                                                                        VkPipelineLayout            layout,
-                                                                        const char                 *shader_name,
-                                                                        VkRenderPass                render_pass);
-
-gsize               gsk_vulkan_blend_mode_pipeline_count_vertex_data   (GskVulkanBlendModePipeline *pipeline);
-void                gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
-                                                                        guchar                     *data,
-                                                                        const graphene_rect_t      *bounds,
-                                                                        const graphene_rect_t      *start_bounds,
-                                                                        const graphene_rect_t      *end_bounds,
-                                                                        GskBlendMode                blend_mode);
-gsize               gsk_vulkan_blend_mode_pipeline_draw                (GskVulkanBlendModePipeline *pipeline,
-                                                                        VkCommandBuffer             command_buffer,
-                                                                        gsize                       offset,
-                                                                        gsize                       n_commands);
-
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanblurpipeline.c b/gsk/gskvulkanblurpipeline.c
deleted file mode 100644 (file)
index 5686e54..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanblurpipelineprivate.h"
-
-struct _GskVulkanBlurPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanBlurInstance GskVulkanBlurInstance;
-
-struct _GskVulkanBlurInstance
-{
-  float rect[4];
-  float tex_rect[4];
-  float blur_radius;
-};
-
-G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanBlurInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_rect),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_blur_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanBlurPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_blur_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_blur_pipeline_class_init (GskVulkanBlurPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blur_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_blur_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_blur_pipeline_init (GskVulkanBlurPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_blur_pipeline_new (GdkVulkanContext        *context,
-                              VkPipelineLayout         layout,
-                              const char              *shader_name,
-                              VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLUR_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline)
-{
-  return sizeof (GskVulkanBlurInstance);
-}
-
-void
-gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
-                                              guchar                *data,
-                                              const graphene_rect_t *rect,
-                                              const graphene_rect_t *tex_rect,
-                                              double                 blur_radius)
-{
-  GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
-
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->tex_rect[0] = tex_rect->origin.x;
-  instance->tex_rect[1] = tex_rect->origin.y;
-  instance->tex_rect[2] = tex_rect->size.width;
-  instance->tex_rect[3] = tex_rect->size.height;
-  instance->blur_radius = blur_radius;
-}
-
-gsize
-gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
-                               VkCommandBuffer        command_buffer,
-                               gsize                  offset,
-                               gsize                  n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkanblurpipelineprivate.h b/gsk/gskvulkanblurpipelineprivate.h
deleted file mode 100644 (file)
index 0fc2cb6..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBlurPipelineLayout GskVulkanBlurPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BLUR_PIPELINE (gsk_vulkan_blur_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK, VULKAN_BLUR_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_blur_pipeline_new                   (GdkVulkanContext        *context,
-                                                                        VkPipelineLayout         layout,
-                                                                        const char              *shader_name,
-                                                                        VkRenderPass             render_pass);
-
-gsize                   gsk_vulkan_blur_pipeline_count_vertex_data     (GskVulkanBlurPipeline   *pipeline);
-void                    gsk_vulkan_blur_pipeline_collect_vertex_data   (GskVulkanBlurPipeline   *pipeline,
-                                                                        guchar                  *data,
-                                                                        const graphene_rect_t   *rect,
-                                                                        const graphene_rect_t   *tex_rect,
-                                                                        double                   radius);
-gsize                   gsk_vulkan_blur_pipeline_draw                  (GskVulkanBlurPipeline   *pipeline,
-                                                                        VkCommandBuffer          command_buffer,
-                                                                        gsize                    offset,
-                                                                        gsize                    n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanborderpipeline.c b/gsk/gskvulkanborderpipeline.c
deleted file mode 100644 (file)
index a0da439..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanborderpipelineprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-struct _GskVulkanBorderPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
-
-struct _GskVulkanBorderInstance
-{
-  float rect[12];
-  float widths[4];
-  float colors[16];
-};
-
-G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanBorderInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
-      },
-      {
-          .location = 4,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
-      },
-      {
-          .location = 5,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
-      },
-      {
-          .location = 6,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
-      },
-      {
-          .location = 7,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_border_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_border_pipeline_new (GdkVulkanContext        *context,
-                                VkPipelineLayout         layout,
-                                const char              *shader_name,
-                                VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
-{
-  return sizeof (GskVulkanBorderInstance);
-}
-
-void
-gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
-                                                guchar                  *data,
-                                                const GskRoundedRect    *rect,
-                                                const float              widths[4],
-                                                const GdkRGBA            colors[4])
-{
-  GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
-  guint i;
-
-  gsk_rounded_rect_to_float (rect, instance->rect);
-  for (i = 0; i < 4; i++)
-    {
-      instance->widths[i] = widths[i];
-      instance->colors[4 * i + 0] = colors[i].red;
-      instance->colors[4 * i + 1] = colors[i].green;
-      instance->colors[4 * i + 2] = colors[i].blue;
-      instance->colors[4 * i + 3] = colors[i].alpha;
-    }
-}
-
-gsize
-gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
-                                VkCommandBuffer         command_buffer,
-                                gsize                   offset,
-                                gsize                   n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6 * 8, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkanborderpipelineprivate.h b/gsk/gskvulkanborderpipelineprivate.h
deleted file mode 100644 (file)
index d826792..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskroundedrect.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_border_pipeline_new                  (GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_border_pipeline_count_vertex_data    (GskVulkanBorderPipeline        *pipeline);
-void                    gsk_vulkan_border_pipeline_collect_vertex_data  (GskVulkanBorderPipeline        *pipeline,
-                                                                         guchar                         *data,
-                                                                         const GskRoundedRect           *rect,
-                                                                         const float                     widths[4],
-                                                                         const GdkRGBA                   colors[4]);
-gsize                   gsk_vulkan_border_pipeline_draw                 (GskVulkanBorderPipeline        *pipeline,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         gsize                           offset,
-                                                                         gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanboxshadowpipeline.c b/gsk/gskvulkanboxshadowpipeline.c
deleted file mode 100644 (file)
index fb27217..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanboxshadowpipelineprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-struct _GskVulkanBoxShadowPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanBoxShadowInstance GskVulkanBoxShadowInstance;
-
-struct _GskVulkanBoxShadowInstance
-{
-  float outline[12];
-  float color[4];
-  float offset[2];
-  float spread;
-  float blur_radius;
-};
-
-G_DEFINE_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_box_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanBoxShadowInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline),
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 4 * sizeof (float),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 8 * sizeof (float),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, color),
-      },
-      {
-          .location = 4,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, offset),
-      },
-      {
-          .location = 5,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, spread),
-      },
-      {
-          .location = 6,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, blur_radius),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanBoxShadowPipeline *self = GSK_VULKAN_BOX_SHADOW_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_box_shadow_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_class_init (GskVulkanBoxShadowPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_box_shadow_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_box_shadow_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_init (GskVulkanBoxShadowPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext        *context,
-                                    VkPipelineLayout         layout,
-                                    const char              *shader_name,
-                                    VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline)
-{
-  return sizeof (GskVulkanBoxShadowInstance);
-}
-
-void
-gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
-                                                    guchar                     *data,
-                                                    const GskRoundedRect       *outline,
-                                                    const GdkRGBA              *color,
-                                                    float                      dx,
-                                                    float                      dy,
-                                                    float                      spread,
-                                                    float                      blur_radius)
-{
-  GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
-
-  gsk_rounded_rect_to_float (outline, instance->outline);
-  instance->color[0] = color->red;
-  instance->color[1] = color->green;
-  instance->color[2] = color->blue;
-  instance->color[3] = color->alpha;
-  instance->offset[0] = dx;
-  instance->offset[1] = dy;
-  instance->spread = spread;
-  instance->blur_radius = blur_radius;
-}
-
-gsize
-gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
-                                     VkCommandBuffer         command_buffer,
-                                     gsize                   offset,
-                                     gsize                   n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6 * 8, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkanboxshadowpipelineprivate.h b/gsk/gskvulkanboxshadowpipelineprivate.h
deleted file mode 100644 (file)
index 975338b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskroundedrect.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBoxShadowPipelineLayout GskVulkanBoxShadowPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE (gsk_vulkan_box_shadow_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK, VULKAN_BOX_SHADOW_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_box_shadow_pipeline_new              (GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline    *pipeline);
-void                    gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline  *pipeline,
-                                                                         guchar                         *data,
-                                                                         const GskRoundedRect           *outline,
-                                                                         const GdkRGBA                  *color,
-                                                                         float                           dx,
-                                                                         float                           dy,
-                                                                         float                           spread,
-                                                                         float                           blur_radius);
-
-gsize                   gsk_vulkan_box_shadow_pipeline_draw             (GskVulkanBoxShadowPipeline     *pipeline,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         gsize                           offset,
-                                                                         gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c
deleted file mode 100644 (file)
index 291e340..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanmemoryprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanBuffer
-{
-  GdkVulkanContext *vulkan;
-
-  gsize size;
-
-  VkBuffer vk_buffer;
-
-  GskVulkanMemory *memory;
-};
-
-static GskVulkanBuffer *
-gsk_vulkan_buffer_new_internal (GdkVulkanContext  *context,
-                                gsize              size,
-                                VkBufferUsageFlags usage)
-{
-  VkMemoryRequirements requirements;
-  GskVulkanBuffer *self;
-
-  self = g_slice_new0 (GskVulkanBuffer);
-
-  self->vulkan = g_object_ref (context);
-  self->size = size;
-
-  GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context),
-                                &(VkBufferCreateInfo) {
-                                    .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
-                                    .size = size,
-                                    .flags = 0,
-                                    .usage = usage,
-                                    .sharingMode = VK_SHARING_MODE_EXCLUSIVE
-                                },
-                                NULL,
-                                &self->vk_buffer);
-
-  vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context),
-                                 self->vk_buffer,
-                                 &requirements);
-
-  self->memory = gsk_vulkan_memory_new (context,
-                                        requirements.memoryTypeBits,
-                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
-                                        size);
-
-  GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context),
-                                    self->vk_buffer,
-                                    gsk_vulkan_memory_get_device_memory (self->memory),
-                                    0);
-  return self;
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new (GdkVulkanContext  *context,
-                       gsize              size)
-{
-  return gsk_vulkan_buffer_new_internal (context, size,
-                                         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
-                                         | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new_staging (GdkVulkanContext  *context,
-                               gsize              size)
-{
-  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new_download (GdkVulkanContext  *context,
-                                gsize              size)
-{
-  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
-}
-void
-gsk_vulkan_buffer_free (GskVulkanBuffer *self)
-{
-  vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan),
-                   self->vk_buffer,
-                   NULL);
-
-  gsk_vulkan_memory_free (self->memory);
-
-  g_object_unref (self->vulkan);
-
-  g_slice_free (GskVulkanBuffer, self);
-}
-
-VkBuffer
-gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
-{
-  return self->vk_buffer;
-}
-
-guchar *
-gsk_vulkan_buffer_map (GskVulkanBuffer *self)
-{
-  return gsk_vulkan_memory_map (self->memory);
-}
-
-void
-gsk_vulkan_buffer_unmap (GskVulkanBuffer *self)
-{
-  gsk_vulkan_memory_unmap (self->memory);
-}
diff --git a/gsk/gskvulkanbufferprivate.h b/gsk/gskvulkanbufferprivate.h
deleted file mode 100644 (file)
index 700e400..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__
-#define __GSK_VULKAN_BUFFER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBuffer GskVulkanBuffer;
-
-GskVulkanBuffer *       gsk_vulkan_buffer_new                           (GdkVulkanContext       *context,
-                                                                         gsize                   size);
-GskVulkanBuffer *       gsk_vulkan_buffer_new_staging                   (GdkVulkanContext       *context,
-                                                                         gsize                   size);
-GskVulkanBuffer *       gsk_vulkan_buffer_new_download                  (GdkVulkanContext       *context,
-                                                                         gsize                   size);
-void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
-
-VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
-
-guchar *                gsk_vulkan_buffer_map                           (GskVulkanBuffer        *self);
-void                    gsk_vulkan_buffer_unmap                         (GskVulkanBuffer        *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BUFFER_PRIVATE_H__ */
diff --git a/gsk/gskvulkanclip.c b/gsk/gskvulkanclip.c
deleted file mode 100644 (file)
index d927d88..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanclipprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-void
-gsk_vulkan_clip_init_empty (GskVulkanClip         *clip,
-                            const graphene_rect_t *rect)
-{
-  clip->type = GSK_VULKAN_CLIP_NONE;
-  gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
-}
-
-static void
-gsk_vulkan_clip_init_copy (GskVulkanClip *self,
-                           const GskVulkanClip *src)
-{
-  self->type = src->type;
-  gsk_rounded_rect_init_copy (&self->rect, &src->rect);
-}
-
-gboolean
-gsk_vulkan_clip_intersect_rect (GskVulkanClip         *dest,
-                                const GskVulkanClip   *src,
-                                const graphene_rect_t *rect)
-{
-  if (graphene_rect_contains_rect (rect, &src->rect.bounds))
-    {
-      gsk_vulkan_clip_init_copy (dest, src);
-      return TRUE;
-    }
-  if (!graphene_rect_intersection (rect, &src->rect.bounds, NULL))
-    {
-      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      return TRUE;
-    }
-
-  switch (src->type)
-    {
-    case GSK_VULKAN_CLIP_ALL_CLIPPED:
-      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      break;
-
-    case GSK_VULKAN_CLIP_NONE:
-      gsk_vulkan_clip_init_copy (dest, src);
-      if (graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
-        dest->type = GSK_VULKAN_CLIP_RECT;
-      else
-        dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      break;
-
-    case GSK_VULKAN_CLIP_RECT:
-      gsk_vulkan_clip_init_copy (dest, src);
-      if (!graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
-        dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      break;
-
-    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
-    case GSK_VULKAN_CLIP_ROUNDED:
-      if (gsk_rounded_rect_contains_rect (&src->rect, rect))
-        {
-          dest->type = GSK_VULKAN_CLIP_RECT;
-          gsk_rounded_rect_init_from_rect (&dest->rect, rect, 0);
-        }
-      else
-        {
-          /* some points of rect are inside src's rounded rect,
-           * some are outside. */
-          /* XXX: If the 2 rects don't intersect on rounded corners,
-           * we could actually compute a new clip here.
-           */
-          return FALSE;
-        }
-
-    default:
-      g_assert_not_reached ();
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-gboolean
-gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip        *dest,
-                                        const GskVulkanClip  *src,
-                                        const GskRoundedRect *rounded)
-{
-  if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
-    {
-      gsk_vulkan_clip_init_copy (dest, src);
-      return TRUE;
-    }
-  if (!graphene_rect_intersection (&rounded->bounds, &src->rect.bounds, NULL))
-    {
-      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      return TRUE;
-    }
-
-  switch (src->type)
-    {
-    case GSK_VULKAN_CLIP_ALL_CLIPPED:
-      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
-      break;
-
-    case GSK_VULKAN_CLIP_NONE:
-      dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
-      gsk_rounded_rect_init_copy (&dest->rect, rounded);
-      break;
-
-    case GSK_VULKAN_CLIP_RECT:
-      if (graphene_rect_contains_rect (&src->rect.bounds, &rounded->bounds))
-        {
-          dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
-          gsk_rounded_rect_init_copy (&dest->rect, rounded);
-          return TRUE;
-        }
-      /* some points of rect are inside src's rounded rect,
-       * some are outside. */
-      /* XXX: If the 2 rects don't intersect on rounded corners,
-       * we could actually compute a new clip here.
-       */
-      return FALSE;
-
-    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
-    case GSK_VULKAN_CLIP_ROUNDED:
-      /* XXX: improve */
-      return FALSE;
-
-    default:
-      g_assert_not_reached ();
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-gboolean
-gsk_vulkan_clip_transform (GskVulkanClip           *dest,
-                           const GskVulkanClip     *src,
-                           const graphene_matrix_t *transform,
-                           const graphene_rect_t   *viewport)
-{
-  switch (src->type)
-    {
-    default:
-      g_assert_not_reached();
-      return FALSE;
-
-    case GSK_VULKAN_CLIP_ALL_CLIPPED:
-      gsk_vulkan_clip_init_copy (dest, src);
-      return TRUE;
-
-    case GSK_VULKAN_CLIP_NONE:
-      gsk_vulkan_clip_init_empty (dest, viewport);
-      return TRUE;
-
-    case GSK_VULKAN_CLIP_RECT:
-    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
-    case GSK_VULKAN_CLIP_ROUNDED:
-      /* FIXME: Handle 2D operations, in particular transform and scale */
-      return FALSE;
-    }
-}
-
-gboolean
-gsk_vulkan_clip_contains_rect (const GskVulkanClip   *self,
-                               const graphene_rect_t *rect)
-{
-  switch (self->type)
-    {
-    default:
-      g_assert_not_reached();
-    case GSK_VULKAN_CLIP_ALL_CLIPPED:
-      return FALSE;
-
-    case GSK_VULKAN_CLIP_NONE:
-      return TRUE;
-
-    case GSK_VULKAN_CLIP_RECT:
-      return graphene_rect_contains_rect (&self->rect.bounds, rect);
-
-    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
-    case GSK_VULKAN_CLIP_ROUNDED:
-      return gsk_rounded_rect_contains_rect (&self->rect, rect);
-    }
-}
diff --git a/gsk/gskvulkanclipprivate.h b/gsk/gskvulkanclipprivate.h
deleted file mode 100644 (file)
index 10b89ed..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __GSK_VULKAN_CLIP_PRIVATE_H__
-#define __GSK_VULKAN_CLIP_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <graphene.h>
-#include <gsk/gskroundedrect.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
-  /* The whole area is clipped, no drawing is necessary.
-   * This can't be handled by return values because for return
-   * values we return if clips could even be computed.
-   */
-  GSK_VULKAN_CLIP_ALL_CLIPPED,
-  /* No clipping is necessary, but the clip rect is set
-   * to the actual bounds of the underlying framebuffer
-   */
-  GSK_VULKAN_CLIP_NONE,
-  /* The clip is a rectangular area */
-  GSK_VULKAN_CLIP_RECT,
-  /* The clip is a rounded rectangle, and for every corner
-   * corner.width == corner.height is true
-   */
-  GSK_VULKAN_CLIP_ROUNDED_CIRCULAR,
-  /* The clip is a rounded rectangle */
-  GSK_VULKAN_CLIP_ROUNDED
-} GskVulkanClipComplexity;
-
-typedef struct _GskVulkanClip GskVulkanClip;
-
-struct _GskVulkanClip
-{
-  GskVulkanClipComplexity type;
-  GskRoundedRect          rect;
-};
-
-void                    gsk_vulkan_clip_init_empty                      (GskVulkanClip          *clip,
-                                                                         const graphene_rect_t  *rect);
-
-gboolean                gsk_vulkan_clip_intersect_rect                  (GskVulkanClip          *dest,
-                                                                         const GskVulkanClip    *src,
-                                                                         const graphene_rect_t  *rect) G_GNUC_WARN_UNUSED_RESULT;
-gboolean                gsk_vulkan_clip_intersect_rounded_rect          (GskVulkanClip          *dest,
-                                                                         const GskVulkanClip    *src,
-                                                                         const GskRoundedRect   *rounded) G_GNUC_WARN_UNUSED_RESULT;
-gboolean                gsk_vulkan_clip_transform                       (GskVulkanClip          *dest,
-                                                                         const GskVulkanClip    *src,
-                                                                         const graphene_matrix_t*transform,
-                                                                         const graphene_rect_t  *viewport) G_GNUC_WARN_UNUSED_RESULT;
-
-gboolean                gsk_vulkan_clip_contains_rect                   (const GskVulkanClip    *self,
-                                                                         const graphene_rect_t  *rect) G_GNUC_WARN_UNUSED_RESULT;
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_CLIP_PRIVATE_H__ */
diff --git a/gsk/gskvulkancolorpipeline.c b/gsk/gskvulkancolorpipeline.c
deleted file mode 100644 (file)
index cd6867a..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "config.h"
-
-#include "gskvulkancolorpipelineprivate.h"
-
-struct _GskVulkanColorPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanColorInstance GskVulkanColorInstance;
-
-struct _GskVulkanColorInstance
-{
-  float rect[4];
-  float color[4];
-};
-
-G_DEFINE_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_color_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanColorInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanColorInstance, color),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_color_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanColorPipeline *self = GSK_VULKAN_COLOR_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_color_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_color_pipeline_class_init (GskVulkanColorPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_color_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_color_pipeline_init (GskVulkanColorPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_color_pipeline_new (GdkVulkanContext         *context,
-                               VkPipelineLayout         layout,
-                               const char              *shader_name,
-                               VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline)
-{
-  return sizeof (GskVulkanColorInstance);
-}
-
-void
-gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
-                                               guchar                 *data,
-                                               const graphene_rect_t  *rect,
-                                               const GdkRGBA          *color)
-{
-  GskVulkanColorInstance *instance = (GskVulkanColorInstance *) data;
-
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->color[0] = color->red;
-  instance->color[1] = color->green;
-  instance->color[2] = color->blue;
-  instance->color[3] = color->alpha;
-}
-
-gsize
-gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
-                                VkCommandBuffer         command_buffer,
-                                gsize                   offset,
-                                gsize                   n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkancolorpipelineprivate.h b/gsk/gskvulkancolorpipelineprivate.h
deleted file mode 100644 (file)
index b9ae514..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanColorPipelineLayout GskVulkanColorPipelineLayout;
-
-#define GSK_TYPE_VULKAN_COLOR_PIPELINE (gsk_vulkan_color_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK, VULKAN_COLOR_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_color_pipeline_new                   (GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_color_pipeline_count_vertex_data     (GskVulkanColorPipeline         *pipeline);
-void                    gsk_vulkan_color_pipeline_collect_vertex_data   (GskVulkanColorPipeline         *pipeline,
-                                                                         guchar                         *data,
-                                                                         const graphene_rect_t          *rect,
-                                                                         const GdkRGBA                  *color);
-gsize                   gsk_vulkan_color_pipeline_draw                  (GskVulkanColorPipeline         *pipeline,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         gsize                           offset,
-                                                                         gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkancolortextpipeline.c b/gsk/gskvulkancolortextpipeline.c
deleted file mode 100644 (file)
index 9770b27..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "config.h"
-
-#include "gskvulkancolortextpipelineprivate.h"
-
-struct _GskVulkanColorTextPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
-
-struct _GskVulkanColorTextInstance
-{
-  float rect[4];
-  float tex_rect[4];
-};
-
-G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanColorTextInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
-      },
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_color_text_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanColorTextPipeline *self = GSK_VULKAN_COLOR_TEXT_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_color_text_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_color_text_pipeline_class_init (GskVulkanColorTextPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_text_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_color_text_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_color_text_pipeline_init (GskVulkanColorTextPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_color_text_pipeline_new (GdkVulkanContext        *context,
-                                    VkPipelineLayout         layout,
-                                    const char              *shader_name,
-                                    VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, context, layout, shader_name, render_pass,
-                                       VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-gsize
-gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
-                                                  int                         num_instances)
-{
-  return sizeof (GskVulkanColorTextInstance) * num_instances;
-}
-
-void
-gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
-                                                    guchar                     *data,
-                                                    GskVulkanRenderer          *renderer,
-                                                    const graphene_rect_t      *rect,
-                                                    PangoFont                  *font,
-                                                    guint                       total_glyphs,
-                                                    const PangoGlyphInfo       *glyphs,
-                                                    float                       x,
-                                                    float                       y,
-                                                    guint                       start_glyph,
-                                                    guint                       num_glyphs,
-                                                    float                       scale)
-{
-  GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) data;
-  int i;
-  int count = 0;
-  int x_position = 0;
-
-  for (i = 0; i < start_glyph; i++)
-    x_position += glyphs[i].geometry.width;
-
-  for (; i < total_glyphs && count < num_glyphs; i++)
-    {
-      const PangoGlyphInfo *gi = &glyphs[i];
-
-      if (gi->glyph != PANGO_GLYPH_EMPTY)
-        {
-          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
-          GskVulkanColorTextInstance *instance = &instances[count];
-          GskVulkanCachedGlyph *glyph;
-
-          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
-
-          instance->tex_rect[0] = glyph->tx;
-          instance->tex_rect[1] = glyph->ty;
-          instance->tex_rect[2] = glyph->tw;
-          instance->tex_rect[3] = glyph->th;
-
-          instance->rect[0] = x + cx + glyph->draw_x;
-          instance->rect[1] = y + cy + glyph->draw_y;
-          instance->rect[2] = glyph->draw_width;
-          instance->rect[3] = glyph->draw_height;
-
-          count++;
-       }
-     x_position += gi->geometry.width;
-   }
-}
-
-gsize
-gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
-                                     VkCommandBuffer             command_buffer,
-                                     gsize                       offset,
-                                     gsize                       n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkancolortextpipelineprivate.h b/gsk/gskvulkancolortextpipelineprivate.h
deleted file mode 100644 (file)
index 2e46b1c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrendererprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanColorTextPipelineLayout GskVulkanColorTextPipelineLayout;
-
-#define GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE (gsk_vulkan_color_text_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK, VULKAN_COLOR_TEXT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_color_text_pipeline_new                   (GdkVulkanContext               *context,
-                                                                              VkPipelineLayout                layout,
-                                                                              const char                     *shader_name,
-                                                                              VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_color_text_pipeline_count_vertex_data     (GskVulkanColorTextPipeline     *pipeline,
-                                                                              int                             num_instances);
-void                    gsk_vulkan_color_text_pipeline_collect_vertex_data   (GskVulkanColorTextPipeline     *pipeline,
-                                                                              guchar                         *data,
-                                                                              GskVulkanRenderer              *renderer,
-                                                                              const graphene_rect_t          *rect,
-                                                                              PangoFont                      *font,
-                                                                              guint                           total_glyphs,
-                                                                              const PangoGlyphInfo           *glyphs,
-                                                                              float                           x,
-                                                                              float                           y,
-                                                                              guint                           start_glyph,
-                                                                              guint                           num_glyphs,
-                                                                              float                           scale);
-gsize                   gsk_vulkan_color_text_pipeline_draw                  (GskVulkanColorTextPipeline     *pipeline,
-                                                                              VkCommandBuffer                 command_buffer,
-                                                                              gsize                           offset,
-                                                                              gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkancommandpool.c b/gsk/gskvulkancommandpool.c
deleted file mode 100644 (file)
index bcba6a9..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#include "config.h"
-
-#include "gskvulkancommandpoolprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanCommandPool
-{
-  GdkVulkanContext *vulkan;
-
-  VkCommandPool vk_command_pool;
-};
-
-GskVulkanCommandPool *
-gsk_vulkan_command_pool_new (GdkVulkanContext *context)
-{
-  GskVulkanCommandPool *self;
-
-  self = g_slice_new0 (GskVulkanCommandPool);
-
-  self->vulkan = g_object_ref (context);
-
-  GSK_VK_CHECK (vkCreateCommandPool, gdk_vulkan_context_get_device (context),
-                                     &(const VkCommandPoolCreateInfo) {
-                                         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
-                                         .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan),
-                                         .flags = 0
-                                     },
-                                     NULL,
-                                     &self->vk_command_pool);
-
-  return self;
-}
-
-void
-gsk_vulkan_command_pool_free (GskVulkanCommandPool *self)
-{
-  vkDestroyCommandPool (gdk_vulkan_context_get_device (self->vulkan),
-                        self->vk_command_pool,
-                        NULL);
-
-  g_slice_free (GskVulkanCommandPool, self);
-}
-
-void
-gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self)
-{
-  GSK_VK_CHECK (vkResetCommandPool, gdk_vulkan_context_get_device (self->vulkan),
-                                    self->vk_command_pool,
-                                    0);
-}
-
-VkCommandBuffer
-gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self)
-{
-  VkCommandBuffer command_buffer;
-
-  GSK_VK_CHECK (vkAllocateCommandBuffers, gdk_vulkan_context_get_device (self->vulkan),
-                                          &(VkCommandBufferAllocateInfo) {
-                                              .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-                                              .commandPool = self->vk_command_pool,
-                                              .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-                                              .commandBufferCount = 1,
-                                          },
-                                          &command_buffer);
-
-  GSK_VK_CHECK (vkBeginCommandBuffer, command_buffer,
-                                      &(VkCommandBufferBeginInfo) {
-                                          .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-                                          .flags = 0
-                                      });
-
-  return command_buffer;
-}
-
-void
-gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
-                                       VkCommandBuffer       command_buffer,
-                                       gsize                 wait_semaphore_count,
-                                       VkSemaphore          *wait_semaphores,
-                                       gsize                 signal_semaphore_count,
-                                       VkSemaphore          *signal_semaphores,
-                                       VkFence               fence)
-{
-  VkPipelineStageFlags *wait_semaphore_flags = NULL;
-
-  GSK_VK_CHECK (vkEndCommandBuffer, command_buffer);
-
-  if (wait_semaphore_count > 0)
-    {
-      wait_semaphore_flags = alloca (sizeof (VkPipelineStageFlags) * wait_semaphore_count);
-      for (int i = 0; i < wait_semaphore_count; i++)
-        wait_semaphore_flags[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-    }
-
-  GSK_VK_CHECK (vkQueueSubmit, gdk_vulkan_context_get_queue (self->vulkan),
-                               1,
-                               &(VkSubmitInfo) {
-                                  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
-                                  .waitSemaphoreCount = wait_semaphore_count,
-                                  .pWaitSemaphores = wait_semaphores,
-                                  .pWaitDstStageMask = wait_semaphore_flags,
-                                  .commandBufferCount = 1,
-                                  .pCommandBuffers = (VkCommandBuffer[1]) {
-                                      command_buffer
-                                  },
-                                  .signalSemaphoreCount = signal_semaphore_count,
-                                  .pSignalSemaphores = signal_semaphores,
-                               },
-                               fence);
-}
-
diff --git a/gsk/gskvulkancommandpoolprivate.h b/gsk/gskvulkancommandpoolprivate.h
deleted file mode 100644 (file)
index bb362f3..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
-#define __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanCommandPool GskVulkanCommandPool;
-
-GskVulkanCommandPool *  gsk_vulkan_command_pool_new                     (GdkVulkanContext       *context);
-void                    gsk_vulkan_command_pool_free                    (GskVulkanCommandPool   *self);
-
-void                    gsk_vulkan_command_pool_reset                   (GskVulkanCommandPool   *self);
-
-VkCommandBuffer         gsk_vulkan_command_pool_get_buffer              (GskVulkanCommandPool   *self);
-void                    gsk_vulkan_command_pool_submit_buffer           (GskVulkanCommandPool   *self,
-                                                                         VkCommandBuffer         buffer,
-                                                                         gsize                   wait_semaphore_count,
-                                                                         VkSemaphore            *wait_semaphores,
-                                                                         gsize                   signal_semaphores_count,
-                                                                         VkSemaphore            *signal_semaphores,
-                                                                         VkFence                 fence);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__ */
diff --git a/gsk/gskvulkancrossfadepipeline.c b/gsk/gskvulkancrossfadepipeline.c
deleted file mode 100644 (file)
index 679c583..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-#include "config.h"
-
-#include "gskvulkancrossfadepipelineprivate.h"
-
-struct _GskVulkanCrossFadePipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
-
-struct _GskVulkanCrossFadeInstance
-{
-  float rect[4];
-  float start_tex_rect[4];
-  float end_tex_rect[4];
-  float progress;
-};
-
-G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanCrossFadeInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext        *context,
-                                    VkPipelineLayout         layout,
-                                    const char              *shader_name,
-                                    VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
-{
-  return sizeof (GskVulkanCrossFadeInstance);
-}
-
-void
-gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
-                                                    guchar                *data,
-                                                    const graphene_rect_t *bounds,
-                                                    const graphene_rect_t *start_tex_rect,
-                                                    const graphene_rect_t *end_tex_rect,
-                                                    double                 progress)
-{
-  GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data;
-
-  instance->rect[0] = bounds->origin.x;
-  instance->rect[1] = bounds->origin.y;
-  instance->rect[2] = bounds->size.width;
-  instance->rect[3] = bounds->size.height;
-
-  instance->start_tex_rect[0] = start_tex_rect->origin.x;
-  instance->start_tex_rect[1] = start_tex_rect->origin.y;
-  instance->start_tex_rect[2] = start_tex_rect->size.width;
-  instance->start_tex_rect[3] = start_tex_rect->size.height;
-
-  instance->end_tex_rect[0] = end_tex_rect->origin.x;
-  instance->end_tex_rect[1] = end_tex_rect->origin.y;
-  instance->end_tex_rect[2] = end_tex_rect->size.width;
-  instance->end_tex_rect[3] = end_tex_rect->size.height;
-
-  instance->progress = progress;
-}
-
-gsize
-gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
-                                     VkCommandBuffer        command_buffer,
-                                     gsize                  offset,
-                                     gsize                  n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkancrossfadepipelineprivate.h b/gsk/gskvulkancrossfadepipelineprivate.h
deleted file mode 100644 (file)
index da5e820..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout;
-
-#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new                 (GdkVulkanContext           *context,
-                                                                        VkPipelineLayout            layout,
-                                                                        const char                 *shader_name,
-                                                                        VkRenderPass                render_pass);
-
-gsize               gsk_vulkan_cross_fade_pipeline_count_vertex_data   (GskVulkanCrossFadePipeline *pipeline);
-void                gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
-                                                                        guchar                     *data,
-                                                                        const graphene_rect_t      *bounds,
-                                                                        const graphene_rect_t      *start_bounds,
-                                                                        const graphene_rect_t      *end_bounds,
-                                                                        double                      progress);
-gsize               gsk_vulkan_cross_fade_pipeline_draw                (GskVulkanCrossFadePipeline *pipeline,
-                                                                        VkCommandBuffer             command_buffer,
-                                                                        gsize                       offset,
-                                                                        gsize                       n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkaneffectpipeline.c b/gsk/gskvulkaneffectpipeline.c
deleted file mode 100644 (file)
index aa9973c..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#include "config.h"
-
-#include "gskvulkaneffectpipelineprivate.h"
-
-struct _GskVulkanEffectPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance;
-
-struct _GskVulkanEffectInstance
-{
-  float rect[4];
-  float tex_rect[4];
-  float color_matrix[16];
-  float color_offset[4];
-};
-
-G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanEffectInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 4,
-      },
-      {
-          .location = 4,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 8,
-      },
-      {
-          .location = 5,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 12,
-      },
-      {
-          .location = 6,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_effect_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_effect_pipeline_new (GdkVulkanContext        *context,
-                                VkPipelineLayout         layout,
-                                const char              *shader_name,
-                                VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline)
-{
-  return sizeof (GskVulkanEffectInstance);
-}
-
-void
-gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
-                                                guchar                  *data,
-                                                const graphene_rect_t   *rect,
-                                                const graphene_rect_t   *tex_rect,
-                                                const graphene_matrix_t *color_matrix,
-                                                const graphene_vec4_t   *color_offset)
-{
-  GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
-
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->tex_rect[0] = tex_rect->origin.x;
-  instance->tex_rect[1] = tex_rect->origin.y;
-  instance->tex_rect[2] = tex_rect->size.width;
-  instance->tex_rect[3] = tex_rect->size.height;
-  graphene_matrix_to_float (color_matrix, instance->color_matrix);
-  graphene_vec4_to_float (color_offset, instance->color_offset);
-}
-
-gsize
-gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
-                                VkCommandBuffer           command_buffer,
-                                gsize                     offset,
-                                gsize                     n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkaneffectpipelineprivate.h b/gsk/gskvulkaneffectpipelineprivate.h
deleted file mode 100644 (file)
index 45ac6af..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout;
-
-#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_effect_pipeline_new                  (GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_effect_pipeline_count_vertex_data    (GskVulkanEffectPipeline        *pipeline);
-void                    gsk_vulkan_effect_pipeline_collect_vertex_data  (GskVulkanEffectPipeline        *pipeline,
-                                                                         guchar                         *data,
-                                                                         const graphene_rect_t          *rect,
-                                                                         const graphene_rect_t          *tex_rect,
-                                                                         const graphene_matrix_t        *color_matrix,
-                                                                         const graphene_vec4_t          *color_offset);
-gsize                   gsk_vulkan_effect_pipeline_draw                 (GskVulkanEffectPipeline        *pipeline,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         gsize                           offset,
-                                                                         gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanglyphcache.c b/gsk/gskvulkanglyphcache.c
deleted file mode 100644 (file)
index 8d12f5c..0000000
+++ /dev/null
@@ -1,483 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanglyphcacheprivate.h"
-
-#include "gskvulkanimageprivate.h"
-#include "gskdebugprivate.h"
-#include "gskprivate.h"
-
-#include <graphene.h>
-
-/* Parameters for our cache eviction strategy.
- *
- * Each cached glyph has an age that gets reset every time a cached glyph gets used.
- * Glyphs that have not been used for the MAX_AGE frames are considered old. We keep
- * count of the pixels of each atlas that are taken up by old glyphs. We check the
- * fraction of old pixels every CHECK_INTERVAL frames, and if it is above MAX_OLD, then
- * we drop the atlas an all the glyphs contained in it from the cache.
- */
-
-#define MAX_AGE 60
-#define CHECK_INTERVAL 10
-#define MAX_OLD 0.333
-
-
-typedef struct {
-  GskVulkanImage *image;
-  int width, height;
-  int x, y, y0;
-  int num_glyphs;
-  GList *dirty_glyphs;
-  guint old_pixels;
-} Atlas;
-
-struct _GskVulkanGlyphCache {
-  GObject parent_instance;
-
-  GdkVulkanContext *vulkan;
-
-  GHashTable *hash_table;
-  GPtrArray *atlases;
-
-  guint64 timestamp;
-};
-
-struct _GskVulkanGlyphCacheClass {
-  GObjectClass parent_class;
-};
-
-G_DEFINE_TYPE (GskVulkanGlyphCache, gsk_vulkan_glyph_cache, G_TYPE_OBJECT)
-
-static guint    glyph_cache_hash       (gconstpointer v);
-static gboolean glyph_cache_equal      (gconstpointer v1,
-                                        gconstpointer v2);
-static void     glyph_cache_key_free   (gpointer      v);
-static void     glyph_cache_value_free (gpointer      v);
-static void     dirty_glyph_free       (gpointer      v);
-
-static Atlas *
-create_atlas (GskVulkanGlyphCache *cache)
-{
-  Atlas *atlas;
-
-  atlas = g_new0 (Atlas, 1);
-  atlas->width = 512;
-  atlas->height = 512;
-  atlas->y0 = 1;
-  atlas->y = 1;
-  atlas->x = 1;
-  atlas->image = NULL;
-  atlas->num_glyphs = 0;
-  atlas->dirty_glyphs = NULL;
-
-  return atlas;
-}
-
-static void
-free_atlas (gpointer v)
-{
-  Atlas *atlas = v;
-
-  g_clear_object (&atlas->image);
-  g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
-  g_free (atlas);
-}
-
-static void
-gsk_vulkan_glyph_cache_init (GskVulkanGlyphCache *cache)
-{
-  cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
-                                             glyph_cache_key_free, glyph_cache_value_free);
-  cache->atlases = g_ptr_array_new_with_free_func (free_atlas);
-}
-
-static void
-gsk_vulkan_glyph_cache_finalize (GObject *object)
-{
-  GskVulkanGlyphCache *cache = GSK_VULKAN_GLYPH_CACHE (object);
-
-  g_ptr_array_unref (cache->atlases);
-  g_hash_table_unref (cache->hash_table);
-
-  G_OBJECT_CLASS (gsk_vulkan_glyph_cache_parent_class)->finalize (object);
-}
-
-static void
-gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->finalize = gsk_vulkan_glyph_cache_finalize;
-}
-
-typedef struct {
-  PangoFont *font;
-  PangoGlyph glyph;
-  guint scale; /* times 1024 */
-} GlyphCacheKey;
-
-static gboolean
-glyph_cache_equal (gconstpointer v1, gconstpointer v2)
-{
-  const GlyphCacheKey *key1 = v1;
-  const GlyphCacheKey *key2 = v2;
-
-  return key1->font == key2->font &&
-         key1->glyph == key2->glyph &&
-         key1->scale == key2->scale;
-}
-
-static guint
-glyph_cache_hash (gconstpointer v)
-{
-  const GlyphCacheKey *key = v;
-
-  return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
-}
-
-static void
-glyph_cache_key_free (gpointer v)
-{
-  GlyphCacheKey *f = v;
-
-  g_object_unref (f->font);
-  g_free (f);
-}
-
-static void
-glyph_cache_value_free (gpointer v)
-{
-  g_free (v);
-}
-
-typedef struct {
-  GlyphCacheKey *key;
-  GskVulkanCachedGlyph *value;
-  cairo_surface_t *surface;
-} DirtyGlyph;
-
-static void
-dirty_glyph_free (gpointer v)
-{
-  DirtyGlyph *glyph = v;
-
-  if (glyph->surface)
-    cairo_surface_destroy (glyph->surface);
-  g_free (glyph);
-}
-
-static void
-add_to_cache (GskVulkanGlyphCache  *cache,
-              GlyphCacheKey        *key,
-              GskVulkanCachedGlyph *value)
-{
-  Atlas *atlas;
-  int i;
-  DirtyGlyph *dirty;
-  int width = value->draw_width * key->scale / 1024;
-  int height = value->draw_height * key->scale / 1024;
-
-  for (i = 0; i < cache->atlases->len; i++)
-    {
-      int x, y, y0;
-
-      atlas = g_ptr_array_index (cache->atlases, i);
-      x = atlas->x;
-      y = atlas->y;
-      y0 = atlas->y0;
-
-      if (atlas->x + width + 1 >= atlas->width)
-        {
-          /* start a new row */
-          y0 = y + 1;
-          x = 1;
-        }
-
-      if (y0 + height + 1 >= atlas->height)
-        continue;
-
-      atlas->y0 = y0;
-      atlas->x = x;
-      atlas->y = y;
-      break;
-    }
-
-  if (i == cache->atlases->len)
-    {
-      atlas = create_atlas (cache);
-      g_ptr_array_add (cache->atlases, atlas);
-    }
-
-  value->tx = (float)atlas->x / atlas->width;
-  value->ty = (float)atlas->y0 / atlas->height;
-  value->tw = (float)width / atlas->width;
-  value->th = (float)height / atlas->height;
-
-  value->texture_index = i;
-
-  dirty = g_new (DirtyGlyph, 1);
-  dirty->key = key;
-  dirty->value = value;
-  atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
-
-  atlas->x = atlas->x + width + 1;
-  atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
-
-  atlas->num_glyphs++;
-
-#ifdef G_ENABLE_DEBUG
-  if (GSK_DEBUG_CHECK(GLYPH_CACHE))
-    {
-      g_print ("Glyph cache:\n");
-      for (i = 0; i < cache->atlases->len; i++)
-        {
-          atlas = g_ptr_array_index (cache->atlases, i);
-          g_print ("\tAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
-                   i, atlas->width, atlas->height,
-                   atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
-                   100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
-                   atlas->x, atlas->y0, atlas->y);
-        }
-    }
-#endif
-}
-
-static void
-render_glyph (Atlas          *atlas,
-              DirtyGlyph     *glyph,
-              GskImageRegion *region)
-{
-  GlyphCacheKey *key = glyph->key;
-  GskVulkanCachedGlyph *value = glyph->value;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  PangoGlyphString glyphs;
-  PangoGlyphInfo gi;
-
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        value->draw_width * key->scale / 1024,
-                                        value->draw_height * key->scale / 1024);
-  cairo_surface_set_device_scale (surface, key->scale / 1024.0, key->scale / 1024.0);
-
-  cr = cairo_create (surface);
-  cairo_set_source_rgba (cr, 1, 1, 1, 1);
-
-  gi.glyph = key->glyph;
-  gi.geometry.width = value->draw_width * 1024;
-  if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
-    gi.geometry.x_offset = 0;
-  else
-    gi.geometry.x_offset = - value->draw_x * 1024;
-  gi.geometry.y_offset = - value->draw_y * 1024;
-
-  glyphs.num_glyphs = 1;
-  glyphs.glyphs = &gi;
-
-  pango_cairo_show_glyph_string (cr, key->font, &glyphs);
-
-  cairo_destroy (cr);
-
-  glyph->surface = surface;
-
-  region->data = cairo_image_surface_get_data (surface);
-  region->width = cairo_image_surface_get_width (surface);
-  region->height = cairo_image_surface_get_height (surface);
-  region->stride = cairo_image_surface_get_stride (surface);
-  region->x = (gsize)(value->tx * atlas->width);
-  region->y = (gsize)(value->ty * atlas->height);
-}
-
-static void
-upload_dirty_glyphs (Atlas             *atlas,
-                     GskVulkanUploader *uploader)
-{
-  GList *l;
-  guint num_regions;
-  GskImageRegion *regions;
-  int i;
-
-  num_regions = g_list_length (atlas->dirty_glyphs);
-  regions = alloca (sizeof (GskImageRegion) * num_regions);
-
-  for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
-    render_glyph (atlas, (DirtyGlyph *)l->data, &regions[i]);
-
-  GSK_NOTE (GLYPH_CACHE,
-            g_print ("uploading %d glyphs to cache\n", num_regions));
-
-  gsk_vulkan_image_upload_regions (atlas->image, uploader, num_regions, regions);
-
-  g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
-  atlas->dirty_glyphs = NULL;
-}
-
-GskVulkanGlyphCache *
-gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan)
-{
-  GskVulkanGlyphCache *cache;
-
-  cache = GSK_VULKAN_GLYPH_CACHE (g_object_new (GSK_TYPE_VULKAN_GLYPH_CACHE, NULL));
-  cache->vulkan = vulkan;
-  g_ptr_array_add (cache->atlases, create_atlas (cache));
-
-  return cache;
-}
-
-GskVulkanCachedGlyph *
-gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
-                               gboolean             create,
-                               PangoFont           *font,
-                               PangoGlyph           glyph,
-                               float                scale)
-{
-  GlyphCacheKey lookup_key;
-  GskVulkanCachedGlyph *value;
-
-  lookup_key.font = font;
-  lookup_key.glyph = glyph;
-  lookup_key.scale = (guint)(scale * 1024);
-
-  value = g_hash_table_lookup (cache->hash_table, &lookup_key);
-
-  if (value)
-    {
-      if (cache->timestamp - value->timestamp >= MAX_AGE)
-        {
-          Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
-
-          atlas->old_pixels -= value->draw_width * value->draw_height;
-          value->timestamp = cache->timestamp;
-        }
-    }
-
-  if (create && value == NULL)
-    {
-      GlyphCacheKey *key;
-      PangoRectangle ink_rect;
-
-      key = g_new (GlyphCacheKey, 1);
-      value = g_new0 (GskVulkanCachedGlyph, 1);
-
-      pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
-      pango_extents_to_pixels (&ink_rect, NULL);
-
-      value->draw_x = ink_rect.x;
-      value->draw_y = ink_rect.y;
-      value->draw_width = ink_rect.width;
-      value->draw_height = ink_rect.height;
-      value->timestamp = cache->timestamp;
-
-      key->font = g_object_ref (font);
-      key->glyph = glyph;
-      key->scale = (guint)(scale * 1024);
-
-      if (ink_rect.width > 0 && ink_rect.height > 0)
-        add_to_cache (cache, key, value);
-
-      g_hash_table_insert (cache->hash_table, key, value);
-    }
-
-  return value;
-}
-
-GskVulkanImage *
-gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
-                                        GskVulkanUploader   *uploader,
-                                        guint                index)
-{
-  Atlas *atlas;
-
-  g_return_val_if_fail (index < cache->atlases->len, NULL);
-
-  atlas = g_ptr_array_index (cache->atlases, index);
-
-  if (atlas->image == NULL)
-    atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height);
-
-  if (atlas->dirty_glyphs)
-    upload_dirty_glyphs (atlas, uploader);
-
-  return atlas->image;
-}
-
-void
-gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache)
-{
-  int i, j;
-  guint *drops;
-  guint *shifts;
-  guint len;
-  GHashTableIter iter;
-  GlyphCacheKey *key;
-  GskVulkanCachedGlyph *value;
-  guint dropped = 0;
-
-  cache->timestamp++;
-
-  if (cache->timestamp % CHECK_INTERVAL != 0)
-    return;
-
-  len = cache->atlases->len;
-
-  /* look for glyphs that have grown old since last time */
-  g_hash_table_iter_init (&iter, cache->hash_table);
-  while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
-    {
-      guint age;
-
-      age = cache->timestamp - value->timestamp;
-      if (MAX_AGE <= age && age < MAX_AGE + CHECK_INTERVAL)
-        {
-          Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
-          atlas->old_pixels += value->draw_width * value->draw_height;
-        }
-    }
-
-  drops = g_alloca (sizeof (guint) * len);
-  shifts = g_alloca (sizeof (guint) * len);
-
-  for (i = 0; i < len; i++)
-    {
-      drops[i] = 0;
-      shifts[i] = i;
-    }
-
-  /* look for atlases to drop, and create a mapping of updated texture indices */
-  for (i = cache->atlases->len - 1; i >= 0; i--)
-    {
-      Atlas *atlas = g_ptr_array_index (cache->atlases, i);
-
-      if (atlas->old_pixels > MAX_OLD * atlas->width * atlas->height)
-        {
-          GSK_NOTE(GLYPH_CACHE,
-                   g_print ("Dropping atlas %d (%g.2%% old)\n", i, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height)));
-          g_ptr_array_remove_index (cache->atlases, i);
-
-          drops[i] = 1;
-          for (j = i; j + 1 < len; j++)
-            shifts[j + 1] = shifts[j];
-        }
-    }
-
-  /* no atlas dropped, we're done */
-  if (len == cache->atlases->len)
-    return;
-
-  /* purge glyphs and update texture indices */
-  g_hash_table_iter_init (&iter, cache->hash_table);
-
-  while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
-    {
-      if (drops[value->texture_index])
-        {
-          dropped++;
-          g_hash_table_iter_remove (&iter);
-        }
-      else
-        {
-          value->texture_index = shifts[value->texture_index];
-        }
-    }
-
-  GSK_NOTE(GLYPH_CACHE, g_print ("Dropped %d glyphs\n", dropped));
-}
diff --git a/gsk/gskvulkanglyphcacheprivate.h b/gsk/gskvulkanglyphcacheprivate.h
deleted file mode 100644 (file)
index 6cf223f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
-#define __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
-
-#include <pango/pango.h>
-#include "gskvulkanrendererprivate.h"
-#include "gskvulkanimageprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_GLYPH_CACHE (gsk_vulkan_glyph_cache_get_type ())
-
-G_DECLARE_FINAL_TYPE(GskVulkanGlyphCache, gsk_vulkan_glyph_cache, GSK, VULKAN_GLYPH_CACHE, GObject)
-
-GskVulkanGlyphCache  *gsk_vulkan_glyph_cache_new            (GdkVulkanContext *vulkan);
-
-GskVulkanImage *     gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
-                                                             GskVulkanUploader   *uploader,
-                                                             guint                index);
-
-GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup         (GskVulkanGlyphCache *cache,
-                                                             gboolean             create,
-                                                             PangoFont           *font,
-                                                             PangoGlyph           glyph,
-                                                             float                scale);
-
-void                  gsk_vulkan_glyph_cache_begin_frame    (GskVulkanGlyphCache *cache);
-
-#endif /* __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanimage.c b/gsk/gskvulkanimage.c
deleted file mode 100644 (file)
index 8d3bdb4..0000000
+++ /dev/null
@@ -1,820 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanimageprivate.h"
-
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanmemoryprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-#include <string.h>
-
-struct _GskVulkanUploader
-{
-  GdkVulkanContext *vulkan;
-
-  GskVulkanCommandPool *command_pool;
-
-  GArray *before_buffer_barriers;
-  GArray *before_image_barriers;
-  VkCommandBuffer copy_buffer;
-  GArray *after_buffer_barriers;
-  GArray *after_image_barriers;
-
-  GSList *staging_image_free_list;
-  GSList *staging_buffer_free_list;
-};
-
-struct _GskVulkanImage
-{
-  GObject parent_instance;
-
-  GdkVulkanContext *vulkan;
-
-  gsize width;
-  gsize height;
-  VkImageUsageFlags vk_usage;
-  VkImage vk_image;
-  VkImageView vk_image_view;
-  VkImageLayout vk_image_layout;
-  VkAccessFlags vk_access;
-
-  GskVulkanMemory *memory;
-};
-
-G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, G_TYPE_OBJECT)
-
-GskVulkanUploader *
-gsk_vulkan_uploader_new (GdkVulkanContext     *context,
-                         GskVulkanCommandPool *command_pool)
-{
-  GskVulkanUploader *self;
-
-  self = g_slice_new0 (GskVulkanUploader);
-
-  self->vulkan = g_object_ref (context);
-  self->command_pool = command_pool;
-
-  self->before_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
-  self->after_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
-
-  self->before_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
-  self->after_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
-
-  return self;
-}
-
-void
-gsk_vulkan_uploader_free (GskVulkanUploader *self)
-{
-  gsk_vulkan_uploader_reset (self);
-
-  g_array_unref (self->after_buffer_barriers);
-  g_array_unref (self->before_buffer_barriers);
-  g_array_unref (self->after_image_barriers);
-  g_array_unref (self->before_image_barriers);
-
-  g_object_unref (self->vulkan);
-
-  g_slice_free (GskVulkanUploader, self);
-}
-
-static void
-gsk_vulkan_uploader_add_image_barrier (GskVulkanUploader          *self,
-                                       gboolean                    after,
-                                       GskVulkanImage             *image,
-                                       VkImageLayout               new_layout,
-                                       VkAccessFlags               new_access)
-{
-  GArray *array;
-  VkImageMemoryBarrier barrier = {
-    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-    .srcAccessMask = image->vk_access,
-    .dstAccessMask = new_access,
-    .oldLayout = image->vk_image_layout,
-    .newLayout = new_layout,
-    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
-    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
-    .image = image->vk_image,
-    .subresourceRange = {
-      .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-      .baseMipLevel = 0,
-      .levelCount = 1,
-      .baseArrayLayer = 0,
-      .layerCount = 1
-    }
-  };
-
-  if (after)
-    array = self->after_image_barriers;
-  else
-    array = self->before_image_barriers;
-
-  g_array_append_val (array, barrier);
-
-  image->vk_image_layout = new_layout;
-  image->vk_access = new_access;
-}
-
-static void
-gsk_vulkan_uploader_add_buffer_barrier (GskVulkanUploader           *self,
-                                        gboolean                     after,
-                                        const VkBufferMemoryBarrier *barrier)
-{
-  GArray *array;
-
-  if (after)
-    array = self->after_buffer_barriers;
-  else
-    array = self->before_buffer_barriers;
-
-  g_array_append_val (array, *barrier);
-}
-
-static VkCommandBuffer
-gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self)
-{
-  if (self->copy_buffer == VK_NULL_HANDLE)
-    self->copy_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-
-  return self->copy_buffer;
-}
-
-void
-gsk_vulkan_uploader_upload (GskVulkanUploader *self)
-{
-  if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0)
-    {
-      VkCommandBuffer command_buffer;
-
-      command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-      vkCmdPipelineBarrier (command_buffer,
-                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
-                            VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
-                            0,
-                            0, NULL,
-                            self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
-                            self->before_image_barriers->len, (VkImageMemoryBarrier *) self->before_image_barriers->data);
-      gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
-      g_array_set_size (self->before_buffer_barriers, 0);
-      g_array_set_size (self->before_image_barriers, 0);
-    }
-
-  /* append these to existing buffer */
-  if (self->after_buffer_barriers->len > 0 || self->after_image_barriers->len > 0)
-    {
-      VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
-      vkCmdPipelineBarrier (command_buffer,
-                            VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
-                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
-                            0,
-                            0, NULL,
-                            self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
-                            self->after_image_barriers->len, (VkImageMemoryBarrier *) self->after_image_barriers->data);
-      g_array_set_size (self->after_buffer_barriers, 0);
-      g_array_set_size (self->after_image_barriers, 0);
-    }
-
-  if (self->copy_buffer != VK_NULL_HANDLE)
-    {
-      gsk_vulkan_command_pool_submit_buffer (self->command_pool, self->copy_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
-      self->copy_buffer = VK_NULL_HANDLE;
-    }
-}
-
-void
-gsk_vulkan_uploader_reset (GskVulkanUploader *self)
-{
-  g_array_set_size (self->before_image_barriers, 0);
-  self->copy_buffer = VK_NULL_HANDLE;
-  g_array_set_size (self->after_image_barriers, 0);
-
-  g_slist_free_full (self->staging_image_free_list, g_object_unref);
-  self->staging_image_free_list = NULL;
-  g_slist_free_full (self->staging_buffer_free_list, (GDestroyNotify) gsk_vulkan_buffer_free);
-  self->staging_buffer_free_list = NULL;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new (GdkVulkanContext      *context,
-                      gsize                  width,
-                      gsize                  height,
-                      VkImageTiling          tiling,
-                      VkImageUsageFlags      usage,
-                      VkImageLayout          layout,
-                      VkAccessFlags          access,
-                      VkMemoryPropertyFlags  memory)
-{
-  VkMemoryRequirements requirements;
-  GskVulkanImage *self;
-
-  self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
-
-  self->vulkan = g_object_ref (context);
-  self->width = width;
-  self->height = height;
-  self->vk_usage = usage;
-  self->vk_image_layout = layout;
-  self->vk_access = access;
-
-  GSK_VK_CHECK (vkCreateImage, gdk_vulkan_context_get_device (context),
-                                &(VkImageCreateInfo) {
-                                    .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-                                    .flags = 0,
-                                    .imageType = VK_IMAGE_TYPE_2D,
-                                    .format = VK_FORMAT_B8G8R8A8_UNORM,
-                                    .extent = { width, height, 1 },
-                                    .mipLevels = 1,
-                                    .arrayLayers = 1,
-                                    .samples = VK_SAMPLE_COUNT_1_BIT,
-                                    .tiling = tiling,
-                                    .usage = usage,
-                                    .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
-                                    .initialLayout = self->vk_image_layout,
-                                },
-                                NULL,
-                                &self->vk_image);
-
-  vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context),
-                                self->vk_image,
-                                &requirements);
-
-  self->memory = gsk_vulkan_memory_new (context,
-                                        requirements.memoryTypeBits,
-                                        memory,
-                                        requirements.size);
-
-  GSK_VK_CHECK (vkBindImageMemory, gdk_vulkan_context_get_device (context),
-                                   self->vk_image,
-                                   gsk_vulkan_memory_get_device_memory (self->memory),
-                                   0);
-  return self;
-}
-
-static void
-gsk_vulkan_image_upload_data (GskVulkanImage *self,
-                              guchar         *data,
-                              gsize           width,
-                              gsize           height,
-                              gsize           data_stride)
-{
-  VkImageSubresource image_res;
-  VkSubresourceLayout image_layout;
-  gsize mem_stride;
-  guchar *mem;
-
-  image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-  image_res.mipLevel = 0;
-  image_res.arrayLayer = 0;
-
-  mem_stride = width * 4;
-  vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
-                               self->vk_image, &image_res, &image_layout);
-
-  mem = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
-
-  if (image_layout.rowPitch == width * 4 && data_stride == mem_stride)
-    {
-      memcpy (mem, data, data_stride * height);
-    }
-  else
-    {
-      for (gsize i = 0; i < height; i++)
-        {
-          memcpy (mem + i * image_layout.rowPitch, data + i * data_stride, width * 4);
-        }
-    }
-
-  gsk_vulkan_memory_unmap (self->memory);
-}
-
-static void
-gsk_vulkan_image_ensure_view (GskVulkanImage *self,
-                              VkFormat        format)
-{
-  if (self->vk_image_view == VK_NULL_HANDLE)
-    GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
-                                   &(VkImageViewCreateInfo) {
-                                       .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-                                       .image = self->vk_image,
-                                       .viewType = VK_IMAGE_VIEW_TYPE_2D,
-                                       .format = format,
-                                       .components = {
-                                           .r = VK_COMPONENT_SWIZZLE_R,
-                                           .g = VK_COMPONENT_SWIZZLE_G,
-                                           .b = VK_COMPONENT_SWIZZLE_B,
-                                           .a = VK_COMPONENT_SWIZZLE_A,
-                                       },
-                                       .subresourceRange = {
-                                           .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-                                           .baseMipLevel = 0,
-                                           .levelCount = 1,
-                                           .baseArrayLayer = 0,
-                                           .layerCount = 1,
-                                       },
-                                   },
-                                   NULL,
-                                   &self->vk_image_view);
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_via_staging_buffer (GskVulkanUploader *uploader,
-                                                   guchar            *data,
-                                                   gsize              width,
-                                                   gsize              height,
-                                                   gsize              stride)
-{
-  GskVulkanImage *self;
-  GskVulkanBuffer *staging;
-  gsize buffer_size = width * height * 4;
-  guchar *mem;
-
-  staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
-  mem = gsk_vulkan_buffer_map (staging);
-
-  if (stride == width * 4)
-    {
-      memcpy (mem, data, stride * height);
-    }
-  else
-    {
-      for (gsize i = 0; i < height; i++)
-        {
-          memcpy (mem + i * width * 4, data + i * stride, width * 4);
-        }
-    }
-
-  gsk_vulkan_buffer_unmap (staging);
-
-  gsk_vulkan_uploader_add_buffer_barrier (uploader,
-                                          FALSE,
-                                          &(VkBufferMemoryBarrier) {
-                                             .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
-                                             .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
-                                             .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
-                                             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
-                                             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
-                                             .buffer = gsk_vulkan_buffer_get_buffer(staging),
-                                             .offset = 0,
-                                             .size = buffer_size,
-                                         });
-
-  self = gsk_vulkan_image_new (uploader->vulkan,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_OPTIMAL,
-                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                               VK_IMAGE_USAGE_SAMPLED_BIT,
-                               VK_IMAGE_LAYOUT_UNDEFINED,
-                               VK_ACCESS_TRANSFER_WRITE_BIT,
-                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         FALSE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                                         VK_ACCESS_TRANSFER_WRITE_BIT);
-
-  vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
-                          gsk_vulkan_buffer_get_buffer (staging),
-                          self->vk_image,
-                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                          1,
-                          (VkBufferImageCopy[1]) {
-                               {
-                                   .bufferOffset = 0,
-                                   .imageSubresource = {
-                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-                                       .mipLevel = 0,
-                                       .baseArrayLayer = 0,
-                                       .layerCount = 1
-                                   },
-                                   .imageOffset = { 0, 0, 0 },
-                                   .imageExtent = {
-                                       .width = width,
-                                       .height = height,
-                                       .depth = 1
-                                   }
-                               }
-                          });
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         TRUE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-                                         VK_ACCESS_SHADER_READ_BIT);
-
-  uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_via_staging_image (GskVulkanUploader *uploader,
-                                                  guchar            *data,
-                                                  gsize              width,
-                                                  gsize              height,
-                                                  gsize              stride)
-{
-  GskVulkanImage *self, *staging;
-
-  staging = gsk_vulkan_image_new (uploader->vulkan,
-                                  width,
-                                  height,
-                                  VK_IMAGE_TILING_LINEAR,
-                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
-                                  VK_IMAGE_LAYOUT_PREINITIALIZED,
-                                  VK_ACCESS_TRANSFER_WRITE_BIT,
-                                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-
-  gsk_vulkan_image_upload_data (staging, data, width, height, stride);
-
-  self = gsk_vulkan_image_new (uploader->vulkan,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_OPTIMAL,
-                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                               VK_IMAGE_USAGE_SAMPLED_BIT,
-                               VK_IMAGE_LAYOUT_UNDEFINED,
-                               VK_ACCESS_TRANSFER_WRITE_BIT,
-                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         FALSE,
-                                         staging,
-                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                                         VK_ACCESS_TRANSFER_READ_BIT);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         FALSE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                                         VK_ACCESS_TRANSFER_WRITE_BIT);
-
-  vkCmdCopyImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
-                  staging->vk_image,
-                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                  self->vk_image,
-                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                  1,
-                  &(VkImageCopy) {
-                      .srcSubresource = {
-                          .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-                          .mipLevel = 0,
-                          .baseArrayLayer = 0,
-                          .layerCount = 1
-                      },
-                      .srcOffset = { 0, 0, 0 },
-                      .dstSubresource = {
-                          .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-                          .mipLevel = 0,
-                          .baseArrayLayer = 0,
-                          .layerCount = 1
-                      },
-                      .dstOffset = { 0, 0, 0 },
-                      .extent = {
-                          .width = width,
-                          .height = height,
-                          .depth = 1
-                      }
-                  });
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         TRUE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-                                         VK_ACCESS_SHADER_READ_BIT);
-
-  uploader->staging_image_free_list = g_slist_prepend (uploader->staging_image_free_list, staging);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_directly (GskVulkanUploader *uploader,
-                                         guchar            *data,
-                                         gsize              width,
-                                         gsize              height,
-                                         gsize              stride)
-{
-  GskVulkanImage *self;
-
-  self = gsk_vulkan_image_new (uploader->vulkan,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_LINEAR,
-                               VK_IMAGE_USAGE_SAMPLED_BIT,
-                               VK_IMAGE_LAYOUT_PREINITIALIZED,
-                               VK_ACCESS_HOST_WRITE_BIT,
-                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-
-  gsk_vulkan_image_upload_data (self, data, width, height, stride);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         TRUE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-                                         VK_ACCESS_SHADER_READ_BIT);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
-                                guchar            *data,
-                                gsize              width,
-                                gsize              height,
-                                gsize              stride)
-{
-  if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
-    return gsk_vulkan_image_new_from_data_via_staging_buffer (uploader, data, width, height, stride);
-  if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
-    return gsk_vulkan_image_new_from_data_via_staging_image (uploader, data, width, height, stride);
-  else
-    return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
-                                    VkImage           image,
-                                    VkFormat          format,
-                                    gsize             width,
-                                    gsize             height)
-{
-  GskVulkanImage *self;
-
-  self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
-
-  self->vulkan = g_object_ref (context);
-  self->width = width;
-  self->height = height;
-  self->vk_image = image;
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
-                                      gsize             width,
-                                      gsize             height)
-{
-  GskVulkanImage *self;
-
-
-  self = gsk_vulkan_image_new (context,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_OPTIMAL,
-                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
-                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
-                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
-                                gsize             width,
-                                gsize             height)
-{
-  GskVulkanImage *self;
-
-  self = gsk_vulkan_image_new (context,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_OPTIMAL,
-                               VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
-                               VK_IMAGE_LAYOUT_UNDEFINED,
-                               0,
-                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
-                                  gsize             width,
-                                  gsize             height)
-{
-  GskVulkanImage *self;
-
-  self = gsk_vulkan_image_new (context,
-                               width,
-                               height,
-                               VK_IMAGE_TILING_OPTIMAL,
-                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                               VK_IMAGE_USAGE_SAMPLED_BIT |
-                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
-                               VK_IMAGE_LAYOUT_UNDEFINED,
-                               0,
-                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
-  return self;
-}
-
-GdkTexture *
-gsk_vulkan_image_download (GskVulkanImage    *self,
-                           GskVulkanUploader *uploader)
-{
-  GskVulkanBuffer *buffer;
-  GdkTexture *texture;
-  guchar *mem;
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         FALSE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                                         VK_ACCESS_TRANSFER_READ_BIT);
-
-  buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
-
-  vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
-                          self->vk_image,
-                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                          gsk_vulkan_buffer_get_buffer (buffer),
-                          1,
-                          (VkBufferImageCopy[1]) {
-                               {
-                                   .bufferOffset = 0,
-                                   .imageSubresource = {
-                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-                                       .mipLevel = 0,
-                                       .baseArrayLayer = 0,
-                                       .layerCount = 1
-                                   },
-                                   .imageOffset = { 0, 0, 0 },
-                                   .imageExtent = {
-                                       .width = self->width,
-                                       .height = self->height,
-                                       .depth = 1
-                                   }
-                               }
-                          });
-
-  gsk_vulkan_uploader_upload (uploader);
-
-  GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
-
-  mem = gsk_vulkan_buffer_map (buffer);
-  texture = gdk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
-  gsk_vulkan_buffer_unmap (buffer);
-  gsk_vulkan_buffer_free (buffer);
-
-  return texture;
-}
-
-void
-gsk_vulkan_image_upload_regions (GskVulkanImage    *self,
-                                 GskVulkanUploader *uploader,
-                                 guint              num_regions,
-                                 GskImageRegion    *regions)
-{
-  GskVulkanBuffer *staging;
-  guchar *mem;
-  guchar *m;
-  gsize size;
-  gsize offset;
-  VkBufferImageCopy *bufferImageCopy;
-
-  size = 0;
-  for (int i = 0; i < num_regions; i++)
-    size += regions[i].width * regions[i].height * 4;
-
-  staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size);
-  mem = gsk_vulkan_buffer_map (staging);
-
-  bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
-  memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
-
-  offset = 0;
-  for (int i = 0; i < num_regions; i++)
-    {
-      m = mem + offset;
-      if (regions[i].stride == regions[i].width * 4)
-        {
-          memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
-        }
-      else
-        {
-          for (gsize r = 0; r < regions[i].height; i++)
-            memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
-        }
-
-      bufferImageCopy[i].bufferOffset = offset;
-      bufferImageCopy[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-      bufferImageCopy[i].imageSubresource.mipLevel = 0;
-      bufferImageCopy[i].imageSubresource.baseArrayLayer = 0;
-      bufferImageCopy[i].imageSubresource.layerCount = 1;
-      bufferImageCopy[i].imageOffset.x = regions[i].x;
-      bufferImageCopy[i].imageOffset.y = regions[i].y;
-      bufferImageCopy[i].imageOffset.z = 0;
-      bufferImageCopy[i].imageExtent.width = regions[i].width;
-      bufferImageCopy[i].imageExtent.height = regions[i].height;
-      bufferImageCopy[i].imageExtent.depth = 1;
-
-      offset += regions[i].width * regions[i].height * 4;
-    }
-
-  gsk_vulkan_buffer_unmap (staging);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         FALSE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                                         VK_ACCESS_TRANSFER_WRITE_BIT);
-
-  vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
-                          gsk_vulkan_buffer_get_buffer (staging),
-                          self->vk_image,
-                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                          num_regions,
-                          bufferImageCopy);
-
-  gsk_vulkan_uploader_add_image_barrier (uploader,
-                                         TRUE,
-                                         self,
-                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-                                         VK_ACCESS_SHADER_READ_BIT);
-
-  uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
-
-  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-}
-
-static void
-gsk_vulkan_image_finalize (GObject *object)
-{
-  GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
-
-  if (self->vk_image_view != VK_NULL_HANDLE)
-    {
-      vkDestroyImageView (gdk_vulkan_context_get_device (self->vulkan),
-                          self->vk_image_view,
-                          NULL);
-    }
-
-  /* memory is NULL for for_swapchain() images, where we don't own
-   * the VkImage */
-  if (self->memory)
-    {
-      vkDestroyImage (gdk_vulkan_context_get_device (self->vulkan),
-                      self->vk_image,
-                      NULL);
-
-      gsk_vulkan_memory_free (self->memory);
-    }
-
-  g_object_unref (self->vulkan);
-
-  G_OBJECT_CLASS (gsk_vulkan_image_parent_class)->finalize (object);
-}
-
-static void
-gsk_vulkan_image_class_init (GskVulkanImageClass *klass)
-{
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_image_finalize;
-}
-
-static void
-gsk_vulkan_image_init (GskVulkanImage *self)
-{
-}
-
-gsize
-gsk_vulkan_image_get_width (GskVulkanImage *self)
-{
-  return self->width;
-}
-
-gsize
-gsk_vulkan_image_get_height (GskVulkanImage *self)
-{
-  return self->height;
-}
-
-VkImage
-gsk_vulkan_image_get_image (GskVulkanImage *self)
-{
-  return self->vk_image;
-}
-
-VkImageView
-gsk_vulkan_image_get_image_view (GskVulkanImage *self)
-{
-  return self->vk_image_view;
-}
diff --git a/gsk/gskvulkanimageprivate.h b/gsk/gskvulkanimageprivate.h
deleted file mode 100644 (file)
index 20c49aa..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef __GSK_VULKAN_IMAGE_PRIVATE_H__
-#define __GSK_VULKAN_IMAGE_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-#include "gsk/gskvulkancommandpoolprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanUploader GskVulkanUploader;
-
-#define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanImage, gsk_vulkan_image, GSK, VULKAN_IMAGE, GObject)
-
-GskVulkanUploader *     gsk_vulkan_uploader_new                         (GdkVulkanContext       *context,
-                                                                         GskVulkanCommandPool   *command_pool);
-void                    gsk_vulkan_uploader_free                        (GskVulkanUploader      *self);
-
-void                    gsk_vulkan_uploader_reset                       (GskVulkanUploader      *self);
-void                    gsk_vulkan_uploader_upload                      (GskVulkanUploader      *self);
-
-GskVulkanImage *        gsk_vulkan_image_new_for_swapchain              (GdkVulkanContext       *context,
-                                                                         VkImage                 image,
-                                                                         VkFormat                format,
-                                                                         gsize                   width,
-                                                                         gsize                   height);
-GskVulkanImage *        gsk_vulkan_image_new_from_data                  (GskVulkanUploader      *uploader,
-                                                                         guchar                 *data,
-                                                                         gsize                   width,
-                                                                         gsize                   height,
-                                                                         gsize                   stride);
-
-typedef struct {
-  guchar *data;
-  gsize width;
-  gsize height;
-  gsize stride;
-  gsize x;
-  gsize y;
-} GskImageRegion;
-
-void                    gsk_vulkan_image_upload_regions                 (GskVulkanImage         *image,
-                                                                         GskVulkanUploader      *uploader,
-                                                                         guint                   num_regions,
-                                                                         GskImageRegion         *regions);
-GskVulkanImage *        gsk_vulkan_image_new_for_framebuffer            (GdkVulkanContext       *context,
-                                                                         gsize                   width,
-                                                                         gsize                   height);
-GskVulkanImage *        gsk_vulkan_image_new_for_atlas                  (GdkVulkanContext       *context,
-                                                                         gsize                   width,
-                                                                         gsize                   height);
-GskVulkanImage *        gsk_vulkan_image_new_for_texture                (GdkVulkanContext       *context,
-                                                                         gsize                   width,
-                                                                         gsize                   height);
-
-GdkTexture *            gsk_vulkan_image_download                       (GskVulkanImage         *self,
-                                                                         GskVulkanUploader      *uploader);
-
-gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
-gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
-VkImage                 gsk_vulkan_image_get_image                      (GskVulkanImage         *self);
-VkImageView             gsk_vulkan_image_get_image_view                 (GskVulkanImage         *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_IMAGE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanlineargradientpipeline.c b/gsk/gskvulkanlineargradientpipeline.c
deleted file mode 100644 (file)
index 058a2f8..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanlineargradientpipelineprivate.h"
-
-struct _GskVulkanLinearGradientPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance;
-
-struct _GskVulkanLinearGradientInstance
-{
-  float rect[4];
-  float start[2];
-  float end[2];
-  gint32 repeating;
-  gint32 stop_count;
-  float offsets[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS];
-  float colors[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS][4];
-};
-
-G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanLinearGradientInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = 0,
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end),
-      },
-      {
-          .location = 3,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SINT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating),
-      },
-      {
-          .location = 4,
-          .binding = 0,
-          .format = VK_FORMAT_R32_SINT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count),
-      },
-      {
-          .location = 5,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets),
-      },
-      {
-          .location = 6,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets) + sizeof (float) * 4,
-      },
-      {
-          .location = 7,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[0]),
-      },
-      {
-          .location = 8,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[1]),
-      },
-      {
-          .location = 9,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[2]),
-      },
-      {
-          .location = 10,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[3]),
-      },
-      {
-          .location = 11,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[4]),
-      },
-      {
-          .location = 12,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[5]),
-      },
-      {
-          .location = 13,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[6]),
-      },
-      {
-          .location = 14,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[7]),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanLinearGradientPipeline *self = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_linear_gradient_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_class_init (GskVulkanLinearGradientPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_linear_gradient_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_init (GskVulkanLinearGradientPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext        *context,
-                                         VkPipelineLayout         layout,
-                                         const char              *shader_name,
-                                         VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GskVulkanLinearGradientPipeline *pipeline)
-{
-  return sizeof (GskVulkanLinearGradientInstance);
-}
-
-void
-gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline,
-                                                         guchar                    *data,
-                                                         const graphene_rect_t     *rect,
-                                                         const graphene_point_t    *start,
-                                                         const graphene_point_t    *end,
-                                                         gboolean                   repeating,
-                                                         gsize                      n_stops,
-                                                         const GskColorStop        *stops)
-{
-  GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data;
-  gsize i;
-
-  if (n_stops > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
-    {
-      g_warning ("Only %u color stops supported.", GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
-      n_stops = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS;
-    }
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->start[0] = start->x;
-  instance->start[1] = start->y;
-  instance->end[0] = end->x;
-  instance->end[1] = end->y;
-  instance->repeating = repeating;
-  instance->stop_count = n_stops;
-  for (i = 0; i < n_stops; i++)
-    {
-      instance->offsets[i] = stops[i].offset;
-      instance->colors[i][0] = stops[i].color.red;
-      instance->colors[i][1] = stops[i].color.green;
-      instance->colors[i][2] = stops[i].color.blue;
-      instance->colors[i][3] = stops[i].color.alpha;
-    }
-}
-
-gsize
-gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline *pipeline,
-                                   VkCommandBuffer            command_buffer,
-                                   gsize                      offset,
-                                   gsize                      n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkanlineargradientpipelineprivate.h b/gsk/gskvulkanlineargradientpipelineprivate.h
deleted file mode 100644 (file)
index 71b6559..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskrendernode.h"
-
-G_BEGIN_DECLS
-
-#define GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS 8
-
-typedef struct _GskVulkanLinearGradientPipelineLayout GskVulkanLinearGradientPipelineLayout;
-
-#define GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE (gsk_vulkan_linear_gradient_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK, VULKAN_LINEAR_GRADIENT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_linear_gradient_pipeline_new         (GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-
-gsize                   gsk_vulkan_linear_gradient_pipeline_count_vertex_data
-                                                                        (GskVulkanLinearGradientPipeline*pipeline);
-void                    gsk_vulkan_linear_gradient_pipeline_collect_vertex_data
-                                                                        (GskVulkanLinearGradientPipeline*pipeline,
-                                                                         guchar                         *data,
-                                                                         const graphene_rect_t          *rect,
-                                                                         const graphene_point_t         *start,
-                                                                         const graphene_point_t         *end,
-                                                                         gboolean                        repeating,
-                                                                         gsize                           n_stops,
-                                                                         const GskColorStop             *stops);
-gsize                   gsk_vulkan_linear_gradient_pipeline_draw        (GskVulkanLinearGradientPipeline*pipeline,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         gsize                           offset,
-                                                                         gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanmemory.c b/gsk/gskvulkanmemory.c
deleted file mode 100644 (file)
index 1ff4675..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanmemoryprivate.h"
-
-struct _GskVulkanMemory
-{
-  GdkVulkanContext *vulkan;
-
-  gsize size;
-
-  VkDeviceMemory vk_memory;
-};
-
-GskVulkanMemory *
-gsk_vulkan_memory_new (GdkVulkanContext      *context,
-                       uint32_t               allowed_types,
-                       VkMemoryPropertyFlags  flags,
-                       gsize                  size)
-{
-  VkPhysicalDeviceMemoryProperties properties;
-  GskVulkanMemory *self;
-  uint32_t i;
-
-  self = g_slice_new0 (GskVulkanMemory);
-
-  self->vulkan = g_object_ref (context);
-  self->size = size;
-
-  vkGetPhysicalDeviceMemoryProperties (gdk_vulkan_context_get_physical_device (context),
-                                       &properties);
-
-  for (i = 0; i < properties.memoryTypeCount; i++)
-    {
-      if (!(allowed_types & (1 << i)))
-        continue;
-
-      if ((properties.memoryTypes[i].propertyFlags & flags) == flags)
-        break;
-  }
-
-  g_assert (i < properties.memoryTypeCount);
-
-  GSK_VK_CHECK (vkAllocateMemory, gdk_vulkan_context_get_device (context),
-                                  &(VkMemoryAllocateInfo) {
-                                      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
-                                      .allocationSize = size,
-                                      .memoryTypeIndex = i
-                                  },
-                                  NULL,
-                                  &self->vk_memory);
-
-  return self;
-}
-
-void
-gsk_vulkan_memory_free (GskVulkanMemory *self)
-{
-  vkFreeMemory (gdk_vulkan_context_get_device (self->vulkan),
-                self->vk_memory,
-                NULL);
-
-  g_object_unref (self->vulkan);
-
-  g_slice_free (GskVulkanMemory, self);
-}
-
-VkDeviceMemory
-gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self)
-{
-  return self->vk_memory;
-}
-
-guchar *
-gsk_vulkan_memory_map (GskVulkanMemory *self)
-{
-  void *data;
-
-  GSK_VK_CHECK (vkMapMemory, gdk_vulkan_context_get_device (self->vulkan),
-                             self->vk_memory,
-                             0,
-                             self->size,
-                             0,
-                             &data);
-
-  return data;
-}
-
-void
-gsk_vulkan_memory_unmap (GskVulkanMemory *self)
-{
-  vkUnmapMemory (gdk_vulkan_context_get_device (self->vulkan),
-                 self->vk_memory);
-}
-
diff --git a/gsk/gskvulkanmemoryprivate.h b/gsk/gskvulkanmemoryprivate.h
deleted file mode 100644 (file)
index 010c133..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__
-#define __GSK_VULKAN_MEMORY_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanMemory GskVulkanMemory;
-
-GskVulkanMemory *       gsk_vulkan_memory_new                           (GdkVulkanContext       *context,
-                                                                         uint32_t                allowed_types,
-                                                                         VkMemoryPropertyFlags   properties,
-                                                                         gsize                   size);
-void                    gsk_vulkan_memory_free                          (GskVulkanMemory        *memory);
-
-VkDeviceMemory          gsk_vulkan_memory_get_device_memory             (GskVulkanMemory        *self);
-
-guchar *                gsk_vulkan_memory_map                           (GskVulkanMemory        *self);
-void                    gsk_vulkan_memory_unmap                         (GskVulkanMemory        *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_MEMORY_PRIVATE_H__ */
diff --git a/gsk/gskvulkanpipeline.c b/gsk/gskvulkanpipeline.c
deleted file mode 100644 (file)
index 38d5a57..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanpipelineprivate.h"
-
-#include "gskvulkanpushconstantsprivate.h"
-#include "gskvulkanshaderprivate.h"
-
-#include <graphene.h>
-
-typedef struct _GskVulkanPipelinePrivate GskVulkanPipelinePrivate;
-
-struct _GskVulkanPipelinePrivate
-{
-  GObject parent_instance;
-
-  GdkVulkanContext *context;
-
-  VkPipeline pipeline;
-  VkPipelineLayout layout;
-
-  GskVulkanShader *vertex_shader;
-  GskVulkanShader *fragment_shader;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT)
-
-static void
-gsk_vulkan_pipeline_finalize (GObject *gobject)
-{
-  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (GSK_VULKAN_PIPELINE (gobject));
-  VkDevice device;
-
-  device = gdk_vulkan_context_get_device (priv->context);
-
-  vkDestroyPipeline (device,
-                     priv->pipeline,
-                     NULL);
-
-  g_clear_pointer (&priv->fragment_shader, gsk_vulkan_shader_free);
-  g_clear_pointer (&priv->vertex_shader, gsk_vulkan_shader_free);
-
-  G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_pipeline_class_init (GskVulkanPipelineClass *klass)
-{
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_pipeline_finalize;
-}
-
-static void
-gsk_vulkan_pipeline_init (GskVulkanPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_pipeline_new (GType                    pipeline_type,
-                         GdkVulkanContext        *context,
-                         VkPipelineLayout         layout,
-                         const char              *shader_name,
-                         VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
-                                       VK_BLEND_FACTOR_ONE,
-                                       VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-GskVulkanPipeline *
-gsk_vulkan_pipeline_new_full (GType                    pipeline_type,
-                              GdkVulkanContext        *context,
-                              VkPipelineLayout         layout,
-                              const char              *shader_name,
-                              VkRenderPass             render_pass,
-                              VkBlendFactor            srcBlendFactor,
-                              VkBlendFactor            dstBlendFactor)
-{
-  GskVulkanPipelinePrivate *priv;
-  GskVulkanPipeline *self;
-  VkDevice device;
-
-  g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
-  g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
-  g_return_val_if_fail (shader_name != NULL, NULL);
-  g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
-
-  self = g_object_new (pipeline_type, NULL);
-
-  priv = gsk_vulkan_pipeline_get_instance_private (self);
-
-  device = gdk_vulkan_context_get_device (context);
-
-  priv->context = context;
-  priv->layout = layout;
-
-  priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
-  priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
-
-  GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
-                                           VK_NULL_HANDLE,
-                                           1,
-                                           &(VkGraphicsPipelineCreateInfo) {
-                                               .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
-                                               .stageCount = 2,
-                                               .pStages = (VkPipelineShaderStageCreateInfo[2]) {
-                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
-                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
-                                               },
-                                               .pVertexInputState = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self),
-                                               .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
-                                                   .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
-                                                   .primitiveRestartEnable = VK_FALSE,
-                                               },
-                                               .pTessellationState = NULL,
-                                               .pViewportState = &(VkPipelineViewportStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
-                                                   .viewportCount = 1,
-                                                   .scissorCount = 1
-                                               },
-                                               .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
-                                                   .depthClampEnable = VK_FALSE,
-                                                   .rasterizerDiscardEnable = VK_FALSE,
-                                                   .polygonMode = VK_POLYGON_MODE_FILL,
-                                                   .cullMode = VK_CULL_MODE_BACK_BIT,
-                                                   .frontFace = VK_FRONT_FACE_CLOCKWISE,
-                                                   .lineWidth = 1.0f,
-                                               },
-                                               .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-                                                   .rasterizationSamples = 1,
-                                               },
-                                               .pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
-                                               },
-                                               .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
-                                                   .attachmentCount = 1,
-                                                   .pAttachments = (VkPipelineColorBlendAttachmentState []) {
-                                                       {
-                                                           .blendEnable = VK_TRUE,
-                                                           .colorBlendOp = VK_BLEND_OP_ADD,
-                                                           .srcColorBlendFactor = srcBlendFactor,
-                                                           .dstColorBlendFactor = dstBlendFactor,
-                                                           .alphaBlendOp = VK_BLEND_OP_ADD,
-                                                           .srcAlphaBlendFactor = srcBlendFactor,
-                                                           .dstAlphaBlendFactor = dstBlendFactor,
-                                                           .colorWriteMask = VK_COLOR_COMPONENT_A_BIT
-                                                                           | VK_COLOR_COMPONENT_R_BIT
-                                                                           | VK_COLOR_COMPONENT_G_BIT
-                                                                           | VK_COLOR_COMPONENT_B_BIT
-                                                       },
-                                                   }
-                                               },
-                                               .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
-                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
-                                                   .dynamicStateCount = 2,
-                                                   .pDynamicStates = (VkDynamicState[2]) {
-                                                       VK_DYNAMIC_STATE_VIEWPORT,
-                                                       VK_DYNAMIC_STATE_SCISSOR
-                                                   },
-                                               },
-                                               .layout = priv->layout,
-                                               .renderPass = render_pass,
-                                               .subpass = 0,
-                                               .basePipelineHandle = VK_NULL_HANDLE,
-                                               .basePipelineIndex = -1,
-                                           },
-                                           NULL,
-                                           &priv->pipeline);
-
-  return self;
-}
-
-VkPipeline
-gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self)
-{
-  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
-
-  return priv->pipeline;
-}
-
-VkPipelineLayout
-gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self)
-{
-  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
-
-  return priv->layout;
-}
diff --git a/gsk/gskvulkanpipelineprivate.h b/gsk/gskvulkanpipelineprivate.h
deleted file mode 100644 (file)
index cd41f82..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_PIPELINE_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-#include "gskdebugprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_PIPELINE (gsk_vulkan_pipeline_get_type ())
-
-G_DECLARE_DERIVABLE_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, GSK, VULKAN_PIPELINE, GObject)
-
-struct _GskVulkanPipelineClass
-{
-  GObjectClass parent_class;
-
-  const VkPipelineVertexInputStateCreateInfo *
-                                (* get_input_state_create_info)         (GskVulkanPipeline              *self);
-};
-
-static inline VkResult
-gsk_vulkan_handle_result (VkResult    res,
-                          const char *called_function)
-{
-  if (res != VK_SUCCESS)
-    {
-      GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res));
-    }
-  return res;
-}
-
-#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
-
-GskVulkanPipeline *     gsk_vulkan_pipeline_new                         (GType                           pipeline_type,
-                                                                         GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass);
-GskVulkanPipeline *     gsk_vulkan_pipeline_new_full                    (GType                           pipeline_type,
-                                                                         GdkVulkanContext               *context,
-                                                                         VkPipelineLayout                layout,
-                                                                         const char                     *shader_name,
-                                                                         VkRenderPass                    render_pass,
-                                                                         VkBlendFactor                   srcBlendFactor,
-                                                                         VkBlendFactor                   dstBlendFactor);
-
-VkPipeline              gsk_vulkan_pipeline_get_pipeline                (GskVulkanPipeline              *self);
-VkPipelineLayout        gsk_vulkan_pipeline_get_pipeline_layout         (GskVulkanPipeline              *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanpushconstants.c b/gsk/gskvulkanpushconstants.c
deleted file mode 100644 (file)
index dc4ae40..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanpushconstantsprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-typedef struct _GskVulkanPushConstantsWire GskVulkanPushConstantsWire;
-
-struct _GskVulkanPushConstantsWire
-{
-  struct {
-    float mvp[16];
-    float clip[12];
-  } common;
-};
-
-void
-gsk_vulkan_push_constants_init (GskVulkanPushConstants  *constants,
-                                const graphene_matrix_t *mvp,
-                                const graphene_rect_t   *viewport)
-{
-  graphene_matrix_init_from_matrix (&constants->mvp, mvp);
-  gsk_vulkan_clip_init_empty (&constants->clip, viewport);
-}
-
-void
-gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants       *self,
-                                     const GskVulkanPushConstants *src)
-{
-  *self = *src;
-}
-
-gboolean
-gsk_vulkan_push_constants_transform (GskVulkanPushConstants       *self,
-                                     const GskVulkanPushConstants *src,
-                                     const graphene_matrix_t      *transform,
-                                     const graphene_rect_t        *viewport)
-
-{
-  if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
-    return FALSE;
-
-  graphene_matrix_multiply (transform, &src->mvp, &self->mvp);
-  return TRUE;
-}
-
-gboolean
-gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants       *self,
-                                          const GskVulkanPushConstants *src,
-                                          const graphene_rect_t        *rect)
-{
-  if (!gsk_vulkan_clip_intersect_rect (&self->clip, &src->clip, rect))
-    return FALSE;
-
-  graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
-  return TRUE;
-}
-
-gboolean
-gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants       *self,
-                                             const GskVulkanPushConstants *src,
-                                             const GskRoundedRect         *rect)
-{
-  if (!gsk_vulkan_clip_intersect_rounded_rect (&self->clip, &src->clip, rect))
-    return FALSE;
-
-  graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
-  return TRUE;
-}
-
-static void
-gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire   *wire,
-                                     const GskVulkanPushConstants *self)
-{
-  graphene_matrix_to_float (&self->mvp, wire->common.mvp);
-  gsk_rounded_rect_to_float (&self->clip.rect, wire->common.clip);
-}
-
-void
-gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
-                                VkCommandBuffer               command_buffer,
-                                VkPipelineLayout              pipeline_layout)
-{
-  GskVulkanPushConstantsWire wire;
-
-  gsk_vulkan_push_constants_wire_init (&wire, self);
-
-  vkCmdPushConstants (command_buffer,
-                      pipeline_layout,
-                      VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
-                      G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
-                      sizeof (wire.common),
-                      &wire.common);
-}
-
-uint32_t
-gsk_vulkan_push_constants_get_range_count (void)
-{
-  return 1;
-}
-
-const VkPushConstantRange *
-gsk_vulkan_push_constants_get_ranges (void)
-{
-  static const VkPushConstantRange ranges[1] = {
-      {
-          .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
-          .offset = G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
-          .size = sizeof (((GskVulkanPushConstantsWire *) 0)->common)
-      }
-  };
-
-  return ranges;
-}
diff --git a/gsk/gskvulkanpushconstantsprivate.h b/gsk/gskvulkanpushconstantsprivate.h
deleted file mode 100644 (file)
index 541a51f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
-#define __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <graphene.h>
-#include <gsk/gskvulkanclipprivate.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanPushConstants GskVulkanPushConstants;
-
-struct _GskVulkanPushConstants
-{
-  graphene_matrix_t mvp;
-  GskVulkanClip clip;
-};
-
-const VkPushConstantRange *
-                        gsk_vulkan_push_constants_get_ranges            (void) G_GNUC_PURE;
-uint32_t                gsk_vulkan_push_constants_get_range_count       (void) G_GNUC_PURE;
-
-void                    gsk_vulkan_push_constants_init                  (GskVulkanPushConstants         *constants,
-                                                                         const graphene_matrix_t        *mvp,
-                                                                         const graphene_rect_t          *viewport);
-void                    gsk_vulkan_push_constants_init_copy             (GskVulkanPushConstants         *self,
-                                                                         const GskVulkanPushConstants   *src);
-
-gboolean                gsk_vulkan_push_constants_transform             (GskVulkanPushConstants         *self,
-                                                                         const GskVulkanPushConstants   *src,
-                                                                         const graphene_matrix_t        *transform,
-                                                                         const graphene_rect_t          *viewport);
-gboolean                gsk_vulkan_push_constants_intersect_rect        (GskVulkanPushConstants         *self,
-                                                                         const GskVulkanPushConstants   *src,
-                                                                         const graphene_rect_t          *rect);
-gboolean                gsk_vulkan_push_constants_intersect_rounded     (GskVulkanPushConstants         *self,
-                                                                         const GskVulkanPushConstants   *src,
-                                                                         const GskRoundedRect           *rect);
-
-void                    gsk_vulkan_push_constants_push                  (const GskVulkanPushConstants   *self,
-                                                                         VkCommandBuffer                 command_buffer,
-                                                                         VkPipelineLayout                pipeline_layout);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__ */
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
deleted file mode 100644 (file)
index 5d8b241..0000000
+++ /dev/null
@@ -1,761 +0,0 @@
-#include "config.h"
-
-#include "gskprivate.h"
-
-#include "gskvulkanrenderprivate.h"
-
-#include "gskrendererprivate.h"
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkancommandpoolprivate.h"
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrenderpassprivate.h"
-
-#include "gskvulkanblendmodepipelineprivate.h"
-#include "gskvulkanblurpipelineprivate.h"
-#include "gskvulkanborderpipelineprivate.h"
-#include "gskvulkanboxshadowpipelineprivate.h"
-#include "gskvulkancolorpipelineprivate.h"
-#include "gskvulkancolortextpipelineprivate.h"
-#include "gskvulkancrossfadepipelineprivate.h"
-#include "gskvulkaneffectpipelineprivate.h"
-#include "gskvulkanlineargradientpipelineprivate.h"
-#include "gskvulkantextpipelineprivate.h"
-#include "gskvulkantexturepipelineprivate.h"
-#include "gskvulkanpushconstantsprivate.h"
-
-#define DESCRIPTOR_POOL_MAXSETS 128
-#define DESCRIPTOR_POOL_MAXSETS_INCREASE 128
-
-struct _GskVulkanRender
-{
-  GskRenderer *renderer;
-  GdkVulkanContext *vulkan;
-
-  int scale_factor;
-  graphene_rect_t viewport;
-  cairo_region_t *clip;
-
-  GHashTable *framebuffers;
-  GskVulkanCommandPool *command_pool;
-  VkFence fence;
-  VkRenderPass render_pass;
-  VkDescriptorSetLayout descriptor_set_layout;
-  VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
-  GskVulkanUploader *uploader;
-
-  GHashTable *descriptor_set_indexes;
-  VkDescriptorPool descriptor_pool;
-  uint32_t descriptor_pool_maxsets;
-  VkDescriptorSet *descriptor_sets;
-  gsize n_descriptor_sets;
-  GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES];
-
-  GskVulkanImage *target;
-
-  VkSampler sampler;
-  VkSampler repeating_sampler;
-
-  GList *render_passes;
-  GSList *cleanup_images;
-
-  GQuark render_pass_counter;
-  GQuark gpu_time_timer;
-};
-
-static void
-gsk_vulkan_render_setup (GskVulkanRender       *self,
-                         GskVulkanImage        *target,
-                         const graphene_rect_t *rect)
-{
-  GdkWindow *window = gsk_renderer_get_window (self->renderer);
-
-  self->target = g_object_ref (target);
-
-  if (rect)
-    {
-      self->viewport = *rect;
-      self->scale_factor = 1;
-      self->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
-                                                      0, 0,
-                                                      gsk_vulkan_image_get_width (target),
-                                                      gsk_vulkan_image_get_height (target)
-                                                  });
-    }
-  else
-    {
-      self->scale_factor = gdk_window_get_scale_factor (gsk_renderer_get_window (self->renderer));
-      self->viewport = GRAPHENE_RECT_INIT (0, 0,
-                                           gdk_window_get_width (window) * self->scale_factor,
-                                           gdk_window_get_height (window) * self->scale_factor);
-      self->clip = gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer));
-    }
-}
-
-static guint desc_set_index_hash (gconstpointer v);
-static gboolean desc_set_index_equal (gconstpointer v1, gconstpointer v2);
-
-GskVulkanRender *
-gsk_vulkan_render_new (GskRenderer      *renderer,
-                       GdkVulkanContext *context)
-{
-  GskVulkanRender *self;
-  VkDevice device;
-
-  self = g_slice_new0 (GskVulkanRender);
-
-  self->vulkan = context;
-  self->renderer = renderer;
-  self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
-  self->descriptor_set_indexes = g_hash_table_new_full (desc_set_index_hash, desc_set_index_equal, NULL, g_free);
-
-  device = gdk_vulkan_context_get_device (self->vulkan);
-
-  self->command_pool = gsk_vulkan_command_pool_new (self->vulkan);
-  GSK_VK_CHECK (vkCreateFence, device,
-                               &(VkFenceCreateInfo) {
-                                   .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
-                                   .flags = VK_FENCE_CREATE_SIGNALED_BIT
-                               },
-                               NULL,
-                               &self->fence);
-
-  self->descriptor_pool_maxsets = DESCRIPTOR_POOL_MAXSETS;
-  GSK_VK_CHECK (vkCreateDescriptorPool, device,
-                                        &(VkDescriptorPoolCreateInfo) {
-                                            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-                                            .maxSets = self->descriptor_pool_maxsets,
-                                            .poolSizeCount = 1,
-                                            .pPoolSizes = (VkDescriptorPoolSize[1]) {
-                                                {
-                                                    .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-                                                    .descriptorCount = self->descriptor_pool_maxsets
-                                                }
-                                            }
-                                        },
-                                        NULL,
-                                        &self->descriptor_pool);
-
-  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
-                                    &(VkRenderPassCreateInfo) {
-                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-                                        .attachmentCount = 1,
-                                        .pAttachments = (VkAttachmentDescription[]) {
-                                           {
-                                              .format = gdk_vulkan_context_get_image_format (self->vulkan),
-                                              .samples = VK_SAMPLE_COUNT_1_BIT,
-                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
-                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
-                                              .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-                                           }
-                                        },
-                                        .subpassCount = 1,
-                                        .pSubpasses = (VkSubpassDescription []) {
-                                           {
-                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                              .inputAttachmentCount = 0,
-                                              .colorAttachmentCount = 1,
-                                              .pColorAttachments = (VkAttachmentReference []) {
-                                                 {
-                                                    .attachment = 0,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pResolveAttachments = (VkAttachmentReference []) {
-                                                  {
-                                                     .attachment = VK_ATTACHMENT_UNUSED,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pDepthStencilAttachment = NULL,
-                                            }
-                                         },
-                                         .dependencyCount = 0
-                                      },
-                                      NULL,
-                                      &self->render_pass);
-
-  GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
-                                             &(VkDescriptorSetLayoutCreateInfo) {
-                                                 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-                                                 .bindingCount = 1,
-                                                 .pBindings = (VkDescriptorSetLayoutBinding[1]) {
-                                                     {
-                                                         .binding = 0,
-                                                         .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-                                                         .descriptorCount = 1,
-                                                         .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
-                                                     }
-                                                 }
-                                             },
-                                             NULL,
-                                             &self->descriptor_set_layout);
-
-  for (guint i = 0; i < 3; i++)
-    {
-      VkDescriptorSetLayout layouts[3] = {
-        self->descriptor_set_layout,
-        self->descriptor_set_layout,
-        self->descriptor_set_layout
-      };
-
-      GSK_VK_CHECK (vkCreatePipelineLayout, device,
-                                            &(VkPipelineLayoutCreateInfo) {
-                                                .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-                                                .setLayoutCount = i,
-                                                .pSetLayouts = layouts,
-                                                .pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
-                                                .pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
-                                            },
-                                            NULL,
-                                            &self->pipeline_layout[i]);
-    }
-
-  GSK_VK_CHECK (vkCreateSampler, device,
-                                 &(VkSamplerCreateInfo) {
-                                     .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
-                                     .magFilter = VK_FILTER_LINEAR,
-                                     .minFilter = VK_FILTER_LINEAR,
-                                     .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
-                                     .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
-                                     .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
-                                     .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
-                                     .unnormalizedCoordinates = VK_FALSE,
-                                     .maxAnisotropy = 1.0,
-                                 },
-                                 NULL,
-                                 &self->sampler);
-
-  GSK_VK_CHECK (vkCreateSampler, device,
-                                 &(VkSamplerCreateInfo) {
-                                     .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
-                                     .magFilter = VK_FILTER_LINEAR,
-                                     .minFilter = VK_FILTER_LINEAR,
-                                     .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
-                                     .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
-                                     .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
-                                     .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
-                                     .unnormalizedCoordinates = VK_FALSE,
-                                     .maxAnisotropy = 1.0,
-                                 },
-                                 NULL,
-                                 &self->repeating_sampler);
-
-  self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
-
-#ifdef G_ENABLE_DEBUG
-  self->render_pass_counter = g_quark_from_static_string ("render-passes");
-  self->gpu_time_timer = g_quark_from_static_string ("gpu-time");
-#endif
-
-  return self;
-}
-
-typedef struct {
-  VkFramebuffer framebuffer;
-} HashFramebufferEntry;
-
-static void
-gsk_vulkan_render_remove_framebuffer_from_image (gpointer  data,
-                                                 GObject  *image)
-{
-  GskVulkanRender *self = data;
-  HashFramebufferEntry *fb;
-
-  fb = g_hash_table_lookup (self->framebuffers, image);
-  g_hash_table_remove (self->framebuffers, image);
-
-  vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
-                        fb->framebuffer,
-                        NULL);
-
-  g_slice_free (HashFramebufferEntry, fb);
-}
-
-VkFramebuffer
-gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
-                                   GskVulkanImage  *image)
-{
-  HashFramebufferEntry *fb;
-
-  fb = g_hash_table_lookup (self->framebuffers, image);
-  if (fb)
-    return fb->framebuffer;
-
-  fb = g_slice_new0 (HashFramebufferEntry);
-  GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
-                                     &(VkFramebufferCreateInfo) {
-                                         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-                                         .renderPass = self->render_pass,
-                                         .attachmentCount = 1,
-                                         .pAttachments = (VkImageView[1]) {
-                                             gsk_vulkan_image_get_image_view (image)
-                                         },
-                                         .width = gsk_vulkan_image_get_width (image),
-                                         .height = gsk_vulkan_image_get_height (image),
-                                         .layers = 1
-                                     },
-                                     NULL,
-                                     &fb->framebuffer);
-  g_hash_table_insert (self->framebuffers, image, fb);
-  g_object_weak_ref (G_OBJECT (image), gsk_vulkan_render_remove_framebuffer_from_image, self);
-
-  return fb->framebuffer;
-}
-
-void
-gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
-                                     GskVulkanImage  *image)
-{
-  self->cleanup_images = g_slist_prepend (self->cleanup_images, image);
-}
-
-void
-gsk_vulkan_render_add_render_pass (GskVulkanRender     *self,
-                                   GskVulkanRenderPass *pass)
-{
-  self->render_passes = g_list_prepend (self->render_passes, pass);
-
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_counter_inc (gsk_renderer_get_profiler (self->renderer), self->render_pass_counter);
-#endif
-}
-
-void
-gsk_vulkan_render_add_node (GskVulkanRender *self,
-                            GskRenderNode   *node)
-{
-  GskVulkanRenderPass *pass;
-  graphene_matrix_t mv;
-
-  graphene_matrix_init_scale (&mv, self->scale_factor, self->scale_factor, 1.0);
-
-  pass = gsk_vulkan_render_pass_new (self->vulkan,
-                                     self->target,
-                                     self->scale_factor,
-                                     &mv,
-                                     &self->viewport,
-                                     self->clip,
-                                     VK_NULL_HANDLE);
-
-  gsk_vulkan_render_add_render_pass (self, pass);
-
-  gsk_vulkan_render_pass_add (pass, self, node);
-}
-
-void
-gsk_vulkan_render_upload (GskVulkanRender *self)
-{
-  GList *l;
-
-  /* gsk_vulkan_render_pass_upload may call gsk_vulkan_render_add_node_for_texture,
-   * prepending new render passes to the list. Therefore, we walk the list from
-   * the end.
-   */
-  for (l = g_list_last (self->render_passes); l; l = l->prev)
-    {
-      GskVulkanRenderPass *pass = l->data;
-      gsk_vulkan_render_pass_upload (pass, self, self->uploader);
-    }
-
-  gsk_vulkan_uploader_upload (self->uploader);
-}
-
-GskVulkanPipeline *
-gsk_vulkan_render_get_pipeline (GskVulkanRender       *self,
-                                GskVulkanPipelineType  type)
-{
-  static const struct {
-    const char *name;
-    guint num_textures;
-    GskVulkanPipeline * (* create_func) (GdkVulkanContext *context, VkPipelineLayout layout, const char *name, VkRenderPass render_pass);
-  } pipeline_info[GSK_VULKAN_N_PIPELINES] = {
-    { "texture",                    1, gsk_vulkan_texture_pipeline_new },
-    { "texture-clip",               1, gsk_vulkan_texture_pipeline_new },
-    { "texture-clip-rounded",       1, gsk_vulkan_texture_pipeline_new },
-    { "color",                      0, gsk_vulkan_color_pipeline_new },
-    { "color-clip",                 0, gsk_vulkan_color_pipeline_new },
-    { "color-clip-rounded",         0, gsk_vulkan_color_pipeline_new },
-    { "linear",                     0, gsk_vulkan_linear_gradient_pipeline_new },
-    { "linear-clip",                0, gsk_vulkan_linear_gradient_pipeline_new },
-    { "linear-clip-rounded",        0, gsk_vulkan_linear_gradient_pipeline_new },
-    { "color-matrix",               1, gsk_vulkan_effect_pipeline_new },
-    { "color-matrix-clip",          1, gsk_vulkan_effect_pipeline_new },
-    { "color-matrix-clip-rounded",  1, gsk_vulkan_effect_pipeline_new },
-    { "border",                     0, gsk_vulkan_border_pipeline_new },
-    { "border-clip",                0, gsk_vulkan_border_pipeline_new },
-    { "border-clip-rounded",        0, gsk_vulkan_border_pipeline_new },
-    { "inset-shadow",               0, gsk_vulkan_box_shadow_pipeline_new },
-    { "inset-shadow-clip",          0, gsk_vulkan_box_shadow_pipeline_new },
-    { "inset-shadow-clip-rounded",  0, gsk_vulkan_box_shadow_pipeline_new },
-    { "outset-shadow",              0, gsk_vulkan_box_shadow_pipeline_new },
-    { "outset-shadow-clip",         0, gsk_vulkan_box_shadow_pipeline_new },
-    { "outset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
-    { "blur",                       1, gsk_vulkan_blur_pipeline_new },
-    { "blur-clip",                  1, gsk_vulkan_blur_pipeline_new },
-    { "blur-clip-rounded",          1, gsk_vulkan_blur_pipeline_new },
-    { "mask",                       1, gsk_vulkan_text_pipeline_new },
-    { "mask-clip",                  1, gsk_vulkan_text_pipeline_new },
-    { "mask-clip-rounded",          1, gsk_vulkan_text_pipeline_new },
-    { "texture",                    1, gsk_vulkan_color_text_pipeline_new },
-    { "texture-clip",               1, gsk_vulkan_color_text_pipeline_new },
-    { "texture-clip-rounded",       1, gsk_vulkan_color_text_pipeline_new },
-    { "crossfade",                  2, gsk_vulkan_cross_fade_pipeline_new },
-    { "crossfade-clip",             2, gsk_vulkan_cross_fade_pipeline_new },
-    { "crossfade-clip-rounded",     2, gsk_vulkan_cross_fade_pipeline_new },
-    { "blendmode",                  2, gsk_vulkan_blend_mode_pipeline_new },
-    { "blendmode-clip",             2, gsk_vulkan_blend_mode_pipeline_new },
-    { "blendmode-clip-rounded",     2, gsk_vulkan_blend_mode_pipeline_new },
-  };
-
-  g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
-
-  if (self->pipelines[type] == NULL)
-    self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
-                                                             self->pipeline_layout[pipeline_info[type].num_textures],
-                                                             pipeline_info[type].name,
-                                                             self->render_pass);
-
-  return self->pipelines[type];
-}
-
-VkDescriptorSet
-gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
-                                      gsize            id)
-{
-  g_assert (id < self->n_descriptor_sets);
-
-  return self->descriptor_sets[id];
-}
-
-typedef struct {
-  gsize index;
-  GskVulkanImage *image;
-  gboolean repeat;
-} HashDescriptorSetIndexEntry;
-
-static guint
-desc_set_index_hash (gconstpointer v)
-{
-  const HashDescriptorSetIndexEntry *e = v;
-
-  return GPOINTER_TO_UINT (e->image) + e->repeat;
-}
-
-static gboolean
-desc_set_index_equal (gconstpointer v1, gconstpointer v2)
-{
-  const HashDescriptorSetIndexEntry *e1 = v1;
-  const HashDescriptorSetIndexEntry *e2 = v2;
-
-  return e1->image == e2->image && e1->repeat == e2->repeat;
-}
-
-gsize
-gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
-                                          GskVulkanImage  *source,
-                                          gboolean         repeat)
-{
-  HashDescriptorSetIndexEntry lookup;
-  HashDescriptorSetIndexEntry *entry;
-
-  g_assert (source != NULL);
-
-  lookup.image = source;
-  lookup.repeat = repeat;
-
-  entry = g_hash_table_lookup (self->descriptor_set_indexes, &lookup);
-  if (entry)
-    return entry->index;
-
-  entry = g_new (HashDescriptorSetIndexEntry, 1);
-  entry->image = source;
-  entry->repeat = repeat;
-  entry->index = g_hash_table_size (self->descriptor_set_indexes);
-  g_hash_table_add (self->descriptor_set_indexes, entry);
-
-  return entry->index;
-}
-
-static void
-gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
-{
-  GHashTableIter iter;
-  gpointer key;
-  VkDevice device;
-  GList *l;
-  guint i, needed_sets;
-
-  device = gdk_vulkan_context_get_device (self->vulkan);
-
-  for (l = self->render_passes; l; l = l->next)
-    {
-      GskVulkanRenderPass *pass = l->data;
-      gsk_vulkan_render_pass_reserve_descriptor_sets (pass, self);
-    }
-  
-  needed_sets = g_hash_table_size (self->descriptor_set_indexes);
-  if (needed_sets > self->n_descriptor_sets)
-    {
-      if (needed_sets > self->descriptor_pool_maxsets)
-        {
-          guint added_sets = needed_sets - self->descriptor_pool_maxsets;
-          added_sets = added_sets + DESCRIPTOR_POOL_MAXSETS_INCREASE - 1;
-          added_sets -= added_sets % DESCRIPTOR_POOL_MAXSETS_INCREASE;
-
-          vkDestroyDescriptorPool (device,
-                                   self->descriptor_pool,
-                                   NULL);
-          self->descriptor_pool_maxsets += added_sets;
-          GSK_VK_CHECK (vkCreateDescriptorPool, device,
-                                                &(VkDescriptorPoolCreateInfo) {
-                                                    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-                                                    .maxSets = self->descriptor_pool_maxsets,
-                                                    .poolSizeCount = 1,
-                                                    .pPoolSizes = (VkDescriptorPoolSize[1]) {
-                                                        {
-                                                            .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-                                                            .descriptorCount = self->descriptor_pool_maxsets
-                                                        }
-                                                    }
-                                                },
-                                                NULL,
-                                                &self->descriptor_pool);
-        }
-      else
-        {
-          GSK_VK_CHECK (vkResetDescriptorPool, device,
-                                               self->descriptor_pool,
-                                               0);
-        }
-
-      self->n_descriptor_sets = needed_sets;
-      self->descriptor_sets = g_renew (VkDescriptorSet, self->descriptor_sets, needed_sets);
-    }
-
-  VkDescriptorSetLayout *layouts = g_newa (VkDescriptorSetLayout, needed_sets);
-  for (i = 0; i < needed_sets; i++)
-    layouts[i] = self->descriptor_set_layout;
-
-  GSK_VK_CHECK (vkAllocateDescriptorSets, device,
-                                          &(VkDescriptorSetAllocateInfo) {
-                                              .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
-                                              .descriptorPool = self->descriptor_pool,
-                                              .descriptorSetCount = needed_sets,
-                                              .pSetLayouts = layouts
-                                          },
-                                          self->descriptor_sets);
-
-  g_hash_table_iter_init (&iter, self->descriptor_set_indexes);
-  while (g_hash_table_iter_next (&iter, &key, NULL))
-    {
-      HashDescriptorSetIndexEntry *entry = key;
-      GskVulkanImage *image = entry->image;
-      gsize id = entry->index;
-      gboolean repeat = entry->repeat;
-
-      vkUpdateDescriptorSets (device,
-                              1,
-                              (VkWriteDescriptorSet[1]) {
-                                  {
-                                      .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-                                      .dstSet = self->descriptor_sets[id],
-                                      .dstBinding = 0,
-                                      .dstArrayElement = 0,
-                                      .descriptorCount = 1,
-                                      .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-                                      .pImageInfo = &(VkDescriptorImageInfo) {
-                                          .sampler = repeat ? self->repeating_sampler : self->sampler,
-                                          .imageView = gsk_vulkan_image_get_image_view (image),
-                                          .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
-                                      }
-                                  }
-                              },
-                              0, NULL);
-    }
-}
-
-void
-gsk_vulkan_render_draw (GskVulkanRender *self)
-{
-  GList *l;
-
-#ifdef G_ENABLE_DEBUG
-  if (GSK_RENDER_MODE_CHECK (SYNC))
-    gsk_profiler_timer_begin (gsk_renderer_get_profiler (self->renderer), self->gpu_time_timer);
-#endif
-
-  gsk_vulkan_render_prepare_descriptor_sets (self);
-
-  for (l = self->render_passes; l; l = l->next)
-    {
-      GskVulkanRenderPass *pass = l->data;
-      VkCommandBuffer command_buffer;
-      gsize wait_semaphore_count;
-      gsize signal_semaphore_count;
-      VkSemaphore *wait_semaphores;
-      VkSemaphore *signal_semaphores;
-
-      wait_semaphore_count = gsk_vulkan_render_pass_get_wait_semaphores (pass, &wait_semaphores);
-      signal_semaphore_count = gsk_vulkan_render_pass_get_signal_semaphores (pass, &signal_semaphores);
-
-      command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-
-      gsk_vulkan_render_pass_draw (pass, self, 3, self->pipeline_layout, command_buffer);
-
-      gsk_vulkan_command_pool_submit_buffer (self->command_pool,
-                                             command_buffer,
-                                             wait_semaphore_count,
-                                             wait_semaphores,
-                                             signal_semaphore_count,
-                                             signal_semaphores,
-                                             l->next != NULL ? VK_NULL_HANDLE : self->fence);
-    }
-
-  if (GSK_RENDER_MODE_CHECK (SYNC))
-    {
-      GskProfiler *profiler;
-      gint64 gpu_time;
-
-      GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan),
-                                     1,
-                                     &self->fence,
-                                     VK_TRUE,
-                                     INT64_MAX);
-
-      profiler = gsk_renderer_get_profiler (self->renderer);
-      gpu_time = gsk_profiler_timer_end (profiler, self->gpu_time_timer);
-      gsk_profiler_timer_set (profiler, self->gpu_time_timer, gpu_time);
-    }
-}
-
-GdkTexture *
-gsk_vulkan_render_download_target (GskVulkanRender *self)
-{
-  gsk_vulkan_uploader_reset (self->uploader);
-
-  return gsk_vulkan_image_download (self->target, self->uploader);
-}
-
-static void
-gsk_vulkan_render_cleanup (GskVulkanRender *self)
-{
-  VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
-
-  /* XXX: Wait for fence here or just in reset()? */
-  GSK_VK_CHECK (vkWaitForFences, device,
-                                 1,
-                                 &self->fence,
-                                 VK_TRUE,
-                                 INT64_MAX);
-
-  GSK_VK_CHECK (vkResetFences, device,
-                               1,
-                               &self->fence);
-
-  gsk_vulkan_uploader_reset (self->uploader);
-
-  gsk_vulkan_command_pool_reset (self->command_pool);
-
-  g_hash_table_remove_all (self->descriptor_set_indexes);
-  GSK_VK_CHECK (vkResetDescriptorPool, device,
-                                       self->descriptor_pool,
-                                       0);
-
-  g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
-  self->render_passes = NULL;
-  g_slist_free_full (self->cleanup_images, g_object_unref);
-  self->cleanup_images = NULL;
-
-  g_clear_pointer (&self->clip, cairo_region_destroy);
-  g_clear_object (&self->target);
-}
-
-void
-gsk_vulkan_render_free (GskVulkanRender *self)
-{
-  GHashTableIter iter;
-  gpointer key, value;
-  VkDevice device;
-  guint i;
-  
-  gsk_vulkan_render_cleanup (self);
-
-  device = gdk_vulkan_context_get_device (self->vulkan);
-
-  g_hash_table_iter_init (&iter, self->framebuffers);
-  while (g_hash_table_iter_next (&iter, &key, &value))
-    {
-      HashFramebufferEntry *fb = value;
-
-      vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
-                            fb->framebuffer,
-                            NULL);
-      g_slice_free (HashFramebufferEntry, fb);
-      g_object_weak_unref (G_OBJECT (key), gsk_vulkan_render_remove_framebuffer_from_image, self);
-      g_hash_table_iter_remove (&iter);
-    }
-  g_hash_table_unref (self->framebuffers);
-
-  for (i = 0; i < GSK_VULKAN_N_PIPELINES; i++)
-    g_clear_object (&self->pipelines[i]);
-
-  g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
-
-  for (i = 0; i < 3; i++)
-    vkDestroyPipelineLayout (device,
-                             self->pipeline_layout[i],
-                             NULL);
-
-  vkDestroyRenderPass (device,
-                       self->render_pass,
-                       NULL);
-
-  vkDestroyDescriptorPool (device,
-                           self->descriptor_pool,
-                           NULL);
-  g_free (self->descriptor_sets);
-  g_hash_table_unref (self->descriptor_set_indexes);
-
-  vkDestroyDescriptorSetLayout (device,
-                                self->descriptor_set_layout,
-                                NULL);
-
-  vkDestroyFence (device,
-                  self->fence,
-                  NULL);
-
-  vkDestroySampler (device,
-                    self->sampler,
-                    NULL);
-
-  vkDestroySampler (device,
-                    self->repeating_sampler,
-                    NULL);
-
-  gsk_vulkan_command_pool_free (self->command_pool);
-
-  g_slice_free (GskVulkanRender, self);
-}
-
-gboolean
-gsk_vulkan_render_is_busy (GskVulkanRender *self)
-{
-  return vkGetFenceStatus (gdk_vulkan_context_get_device (self->vulkan), self->fence) != VK_SUCCESS;
-}
-
-void
-gsk_vulkan_render_reset (GskVulkanRender       *self,
-                         GskVulkanImage        *target,
-                         const graphene_rect_t *rect)
-{
-  gsk_vulkan_render_cleanup (self);
-
-  gsk_vulkan_render_setup (self, target, rect);
-}
-
-GskRenderer *
-gsk_vulkan_render_get_renderer (GskVulkanRender *self)
-{
-  return self->renderer;
-}
diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c
deleted file mode 100644 (file)
index 82c25ec..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanrendererprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskprivate.h"
-#include "gskrendererprivate.h"
-#include "gskrendernodeprivate.h"
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanimageprivate.h"
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrenderprivate.h"
-#include "gskvulkanglyphcacheprivate.h"
-
-#include "gdk/gdktextureprivate.h"
-
-#include <graphene.h>
-
-typedef struct _GskVulkanTextureData GskVulkanTextureData;
-
-struct _GskVulkanTextureData {
-  GdkTexture *texture;
-  GskVulkanImage *image;
-  GskVulkanRenderer *renderer;
-};
-
-#ifdef G_ENABLE_DEBUG
-typedef struct {
-  GQuark frames;
-  GQuark render_passes;
-  GQuark fallback_pixels;
-  GQuark texture_pixels;
-} ProfileCounters;
-
-typedef struct {
-  GQuark cpu_time;
-  GQuark gpu_time;
-} ProfileTimers;
-#endif
-
-struct _GskVulkanRenderer
-{
-  GskRenderer parent_instance;
-
-  GdkVulkanContext *vulkan;
-
-  guint n_targets;
-  GskVulkanImage **targets;
-
-  GskVulkanRender *render;
-
-  GSList *textures;
-
-  GskVulkanGlyphCache *glyph_cache;
-
-#ifdef G_ENABLE_DEBUG
-  ProfileCounters profile_counters;
-  ProfileTimers profile_timers;
-#endif
-};
-
-struct _GskVulkanRendererClass
-{
-  GskRendererClass parent_class;
-};
-
-G_DEFINE_TYPE (GskVulkanRenderer, gsk_vulkan_renderer, GSK_TYPE_RENDERER)
-
-static void
-gsk_vulkan_renderer_free_targets (GskVulkanRenderer *self)
-{
-  guint i;
-
-  for (i = 0; i < self->n_targets; i++)
-    {
-      g_object_unref (self->targets[i]);
-    }
-
-  g_clear_pointer (&self->targets, g_free);
-  self->n_targets = 0;
-}
-
-static void
-gsk_vulkan_renderer_update_images_cb (GdkVulkanContext  *context,
-                                      GskVulkanRenderer *self)
-{
-  GdkWindow *window;
-  gint scale_factor;
-  gsize width, height;
-  guint i;
-
-  gsk_vulkan_renderer_free_targets (self);
-
-  self->n_targets = gdk_vulkan_context_get_n_images (context);
-  self->targets = g_new (GskVulkanImage *, self->n_targets);
-
-  window = gsk_renderer_get_window (GSK_RENDERER (self));
-  scale_factor = gdk_window_get_scale_factor (window);
-  width = gdk_window_get_width (window) * scale_factor;
-  height = gdk_window_get_height (window) * scale_factor;
-
-  for (i = 0; i < self->n_targets; i++)
-    {
-      self->targets[i] = gsk_vulkan_image_new_for_swapchain (self->vulkan,
-                                                             gdk_vulkan_context_get_image (context, i),
-                                                             gdk_vulkan_context_get_image_format (self->vulkan),
-                                                             width, height);
-    }
-}
-
-static gboolean
-gsk_vulkan_renderer_realize (GskRenderer  *renderer,
-                             GdkWindow    *window,
-                             GError      **error)
-{
-  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-
-  self->vulkan = gdk_window_create_vulkan_context (window, error);
-  if (self->vulkan == NULL)
-    return FALSE;
-
-  g_signal_connect (self->vulkan,
-                    "images-updated",
-                    G_CALLBACK (gsk_vulkan_renderer_update_images_cb),
-                    self);
-  gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
-
-  self->render = gsk_vulkan_render_new (renderer, self->vulkan);
-
-  self->glyph_cache = gsk_vulkan_glyph_cache_new (self->vulkan);
-
-  return TRUE;
-}
-
-static void
-gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
-{
-  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-  GSList *l;
-
-  g_clear_object (&self->glyph_cache);
-
-  for (l = self->textures; l; l = l->next)
-    {
-      GskVulkanTextureData *data = l->data;
-
-      data->renderer = NULL;
-      gdk_texture_clear_render_data (data->texture);
-    }
-  g_clear_pointer (&self->textures, (GDestroyNotify) g_slist_free);
-
-  g_clear_pointer (&self->render, gsk_vulkan_render_free);
-
-  gsk_vulkan_renderer_free_targets (self);
-  g_signal_handlers_disconnect_by_func(self->vulkan,
-                                       gsk_vulkan_renderer_update_images_cb,
-                                       self);
-
-  g_clear_object (&self->vulkan);
-}
-
-static GdkTexture *
-gsk_vulkan_renderer_render_texture (GskRenderer           *renderer,
-                                    GskRenderNode         *root,
-                                    const graphene_rect_t *viewport)
-{
-  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-  GskVulkanRender *render;
-  GskVulkanImage *image;
-  GdkTexture *texture;
-#ifdef G_ENABLE_DEBUG
-  GskProfiler *profiler;
-  gint64 cpu_time;
-#endif
-
-#ifdef G_ENABLE_DEBUG
-  profiler = gsk_renderer_get_profiler (renderer);
-  gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
-  gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
-  gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
-  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
-  render = gsk_vulkan_render_new (renderer, self->vulkan);
-
-  image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
-                                                ceil (viewport->size.width),
-                                                ceil (viewport->size.height));
-
-  gsk_vulkan_render_reset (render, image, viewport);
-
-  gsk_vulkan_render_add_node (render, root);
-
-  gsk_vulkan_render_upload (render);
-
-  gsk_vulkan_render_draw (render);
-
-  texture = gsk_vulkan_render_download_target (render);
-
-  g_object_unref (image);
-  gsk_vulkan_render_free (render);
-
-#ifdef G_ENABLE_DEBUG
-  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
-  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
-  gsk_profiler_push_samples (profiler);
-#endif
-
-  return texture;
-}
-
-static void
-gsk_vulkan_renderer_render (GskRenderer   *renderer,
-                            GskRenderNode *root)
-{
-  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-  GskVulkanRender *render;
-#ifdef G_ENABLE_DEBUG
-  GskProfiler *profiler;
-  gint64 cpu_time;
-#endif
-
-#ifdef G_ENABLE_DEBUG
-  profiler = gsk_renderer_get_profiler (renderer);
-  gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
-  gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
-  gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
-  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
-  render = self->render;
-
-  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
-
-  gsk_vulkan_render_add_node (render, root);
-
-  gsk_vulkan_render_upload (render);
-
-  gsk_vulkan_render_draw (render);
-
-#ifdef G_ENABLE_DEBUG
-  gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
-
-  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
-  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
-  gsk_profiler_push_samples (profiler);
-#endif
-}
-
-static GdkDrawingContext *
-gsk_vulkan_renderer_begin_draw_frame (GskRenderer          *renderer,
-                                      const cairo_region_t *region)
-{
-  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-  GdkDrawingContext *result;
-
-  result = gdk_window_begin_draw_frame (gsk_renderer_get_window (renderer),
-                                        GDK_DRAW_CONTEXT (self->vulkan),
-                                        region);
-
-  return result;
-}
-
-static void
-gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
-{
-  GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
-
-  renderer_class->realize = gsk_vulkan_renderer_realize;
-  renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
-  renderer_class->render = gsk_vulkan_renderer_render;
-  renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
-  renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
-}
-
-static void
-gsk_vulkan_renderer_init (GskVulkanRenderer *self)
-{
-#ifdef G_ENABLE_DEBUG
-  GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
-#endif
-
-  gsk_ensure_resources ();
-
-#ifdef G_ENABLE_DEBUG
-  self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
-  self->profile_counters.render_passes = gsk_profiler_add_counter (profiler, "render-passes", "Render passes", FALSE);
-  self->profile_counters.fallback_pixels = gsk_profiler_add_counter (profiler, "fallback-pixels", "Fallback pixels", TRUE);
-  self->profile_counters.texture_pixels = gsk_profiler_add_counter (profiler, "texture-pixels", "Texture pixels", TRUE);
-
-  self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
-  if (GSK_RENDER_MODE_CHECK (SYNC))
-    self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
-#endif
-}
-
-static void
-gsk_vulkan_renderer_clear_texture (gpointer p)
-{
-  GskVulkanTextureData *data = p;
-
-  if (data->renderer != NULL)
-    data->renderer->textures = g_slist_remove (data->renderer->textures, data);
-
-  g_object_unref (data->image);
-
-  g_slice_free (GskVulkanTextureData, data);
-}
-
-GskVulkanImage *
-gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
-                                       GdkTexture        *texture,
-                                       GskVulkanUploader *uploader)
-{
-  GskVulkanTextureData *data;
-  cairo_surface_t *surface;
-  GskVulkanImage *image;
-
-  data = gdk_texture_get_render_data (texture, self);
-  if (data)
-    return g_object_ref (data->image);
-
-  surface = gdk_texture_download_surface (texture);
-  image = gsk_vulkan_image_new_from_data (uploader,
-                                          cairo_image_surface_get_data (surface),
-                                          cairo_image_surface_get_width (surface),
-                                          cairo_image_surface_get_height (surface),
-                                          cairo_image_surface_get_stride (surface));
-  cairo_surface_destroy (surface);
-
-  data = g_slice_new0 (GskVulkanTextureData);
-  data->image = image;
-  data->texture = texture;
-  data->renderer = self;
-
-  if (gdk_texture_set_render_data (texture, self, data, gsk_vulkan_renderer_clear_texture))
-    {
-      g_object_ref (data->image);
-      self->textures = g_slist_prepend (self->textures, data);
-    }
-  else
-    {
-      g_slice_free (GskVulkanTextureData, data);
-    }
-
-  return image;
-}
-
-guint
-gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
-                                 PangoFont         *font,
-                                 PangoGlyph         glyph,
-                                 float              scale)
-{
-  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
-}
-
-GskVulkanImage *
-gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
-                                     GskVulkanUploader  *uploader,
-                                     guint               index)
-{
-  return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
-}
-
-GskVulkanCachedGlyph *
-gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
-                                      PangoFont         *font,
-                                      PangoGlyph         glyph,
-                                      float              scale)
-{
-  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
-}
diff --git a/gsk/gskvulkanrendererprivate.h b/gsk/gskvulkanrendererprivate.h
deleted file mode 100644 (file)
index 42ffc22..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __GSK_VULKAN_RENDERER_PRIVATE_H__
-#define __GSK_VULKAN_RENDERER_PRIVATE_H__
-
-#include <vulkan/vulkan.h>
-#include <gsk/gskrenderer.h>
-
-#include "gsk/gskvulkanimageprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
-
-#define GSK_VULKAN_RENDERER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
-#define GSK_IS_VULKAN_RENDERER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
-#define GSK_VULKAN_RENDERER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
-#define GSK_IS_VULKAN_RENDERER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
-#define GSK_VULKAN_RENDERER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
-
-typedef struct _GskVulkanRenderer                GskVulkanRenderer;
-typedef struct _GskVulkanRendererClass           GskVulkanRendererClass;
-
-GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
-
-GskVulkanImage *        gsk_vulkan_renderer_ref_texture_image           (GskVulkanRenderer      *self,
-                                                                         GdkTexture             *texture,
-                                                                         GskVulkanUploader      *uploader);
-
-typedef struct
-{
-  guint texture_index;
-
-  float tx;
-  float ty;
-  float tw;
-  float th;
-
-  int draw_x;
-  int draw_y;
-  int draw_width;
-  int draw_height;
-
-  guint64 timestamp;
-} GskVulkanCachedGlyph;
-
-guint                  gsk_vulkan_renderer_cache_glyph      (GskVulkanRenderer *renderer,
-                                                             PangoFont         *font,
-                                                             PangoGlyph         glyph,
-                                                             float              scale);
-
-GskVulkanImage *       gsk_vulkan_renderer_ref_glyph_image  (GskVulkanRenderer *self,
-                                                             GskVulkanUploader *uploader,
-                                                             guint              index);
-
-GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
-                                                             PangoFont         *font,
-                                                             PangoGlyph         glyph,
-                                                             float              scale);
-
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
deleted file mode 100644 (file)
index 83fff2d..0000000
+++ /dev/null
@@ -1,1942 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanrenderpassprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskprofilerprivate.h"
-#include "gskrendernodeprivate.h"
-#include "gskrenderer.h"
-#include "gskrendererprivate.h"
-#include "gskroundedrectprivate.h"
-#include "gskvulkanblendmodepipelineprivate.h"
-#include "gskvulkanblurpipelineprivate.h"
-#include "gskvulkanborderpipelineprivate.h"
-#include "gskvulkanboxshadowpipelineprivate.h"
-#include "gskvulkanclipprivate.h"
-#include "gskvulkancolorpipelineprivate.h"
-#include "gskvulkancolortextpipelineprivate.h"
-#include "gskvulkancrossfadepipelineprivate.h"
-#include "gskvulkaneffectpipelineprivate.h"
-#include "gskvulkanlineargradientpipelineprivate.h"
-#include "gskvulkantextpipelineprivate.h"
-#include "gskvulkantexturepipelineprivate.h"
-#include "gskvulkanimageprivate.h"
-#include "gskvulkanpushconstantsprivate.h"
-#include "gskvulkanrendererprivate.h"
-#include "gskprivate.h"
-
-#include <cairo-ft.h>
-
-#define ORTHO_NEAR_PLANE        -10000
-#define ORTHO_FAR_PLANE          10000
-
-typedef union _GskVulkanOp GskVulkanOp;
-typedef struct _GskVulkanOpRender GskVulkanOpRender;
-typedef struct _GskVulkanOpText GskVulkanOpText;
-typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
-
-typedef enum {
-  /* GskVulkanOpRender */
-  GSK_VULKAN_OP_FALLBACK,
-  GSK_VULKAN_OP_FALLBACK_CLIP,
-  GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
-  GSK_VULKAN_OP_SURFACE,
-  GSK_VULKAN_OP_TEXTURE,
-  GSK_VULKAN_OP_COLOR,
-  GSK_VULKAN_OP_LINEAR_GRADIENT,
-  GSK_VULKAN_OP_OPACITY,
-  GSK_VULKAN_OP_BLUR,
-  GSK_VULKAN_OP_COLOR_MATRIX,
-  GSK_VULKAN_OP_BORDER,
-  GSK_VULKAN_OP_INSET_SHADOW,
-  GSK_VULKAN_OP_OUTSET_SHADOW,
-  GSK_VULKAN_OP_REPEAT,
-  GSK_VULKAN_OP_CROSS_FADE,
-  GSK_VULKAN_OP_BLEND_MODE,
-  /* GskVulkanOpText */
-  GSK_VULKAN_OP_TEXT,
-  GSK_VULKAN_OP_COLOR_TEXT,
-  /* GskVulkanOpPushConstants */
-  GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
-} GskVulkanOpType;
-
-/* render ops with 0, 1 or 2 sources */
-struct _GskVulkanOpRender
-{
-  GskVulkanOpType      type;
-  GskRenderNode       *node; /* node that's the source of this op */
-  GskVulkanPipeline   *pipeline; /* pipeline to use */
-  GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
-  GskVulkanImage      *source; /* source image to render */
-  GskVulkanImage      *source2; /* second source image to render (if relevant) */
-  gsize                vertex_offset; /* offset into vertex buffer */
-  gsize                vertex_count; /* number of vertices */
-  gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
-  gsize                descriptor_set_index2; /* descriptor index for the second source (if relevant) */
-  graphene_rect_t      source_rect; /* area that source maps to */
-  graphene_rect_t      source2_rect; /* area that source2 maps to */
-};
-
-struct _GskVulkanOpText
-{
-  GskVulkanOpType      type;
-  GskRenderNode       *node; /* node that's the source of this op */
-  GskVulkanPipeline   *pipeline; /* pipeline to use */
-  GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
-  GskVulkanImage      *source; /* source image to render */
-  gsize                vertex_offset; /* offset into vertex buffer */
-  gsize                vertex_count; /* number of vertices */
-  gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
-  guint                texture_index; /* index of the texture in the glyph cache */
-  guint                start_glyph; /* the first glyph in nodes glyphstring that we render */
-  guint                num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
-  float                scale;
-};
-
-struct _GskVulkanOpPushConstants
-{
-  GskVulkanOpType         type;
-  GskRenderNode          *node; /* node that's the source of this op */
-  GskVulkanPushConstants  constants; /* new constants to push */
-};
-
-union _GskVulkanOp
-{
-  GskVulkanOpType          type;
-  GskVulkanOpRender        render;
-  GskVulkanOpText          text;
-  GskVulkanOpPushConstants constants;
-};
-
-struct _GskVulkanRenderPass
-{
-  GdkVulkanContext *vulkan;
-
-  GArray *render_ops;
-
-  GskVulkanImage *target;
-  int scale_factor;
-  graphene_rect_t viewport;
-  cairo_region_t *clip;
-  graphene_matrix_t mv;
-  graphene_matrix_t p;
-
-  VkRenderPass render_pass;
-  VkSemaphore signal_semaphore;
-  GArray *wait_semaphores;
-  GskVulkanBuffer *vertex_data;
-
-  GQuark fallback_pixels;
-  GQuark texture_pixels;
-};
-
-GskVulkanRenderPass *
-gsk_vulkan_render_pass_new (GdkVulkanContext  *context,
-                            GskVulkanImage    *target,
-                            int                scale_factor,
-                            graphene_matrix_t *mv,
-                            graphene_rect_t   *viewport,
-                            cairo_region_t    *clip,
-                            VkSemaphore        signal_semaphore)
-{
-  GskVulkanRenderPass *self;
-  VkImageLayout final_layout;
-
-  self = g_slice_new0 (GskVulkanRenderPass);
-  self->vulkan = g_object_ref (context);
-  self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
-
-  self->target = g_object_ref (target);
-  self->scale_factor = scale_factor;
-  self->clip = cairo_region_copy (clip);
-  self->viewport = *viewport;
-
-  self->mv = *mv;
-  graphene_matrix_init_ortho (&self->p,
-                              viewport->origin.x, viewport->origin.x + viewport->size.width,
-                              viewport->origin.y, viewport->origin.y + viewport->size.height,
-                              ORTHO_NEAR_PLANE,
-                              ORTHO_FAR_PLANE);
-
-  if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
-    final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-  else
-    final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
-                                    &(VkRenderPassCreateInfo) {
-                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-                                        .attachmentCount = 1,
-                                        .pAttachments = (VkAttachmentDescription[]) {
-                                           {
-                                              .format = gdk_vulkan_context_get_image_format (self->vulkan),
-                                              .samples = VK_SAMPLE_COUNT_1_BIT,
-                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
-                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
-                                              .finalLayout = final_layout
-                                           }
-                                        },
-                                        .subpassCount = 1,
-                                        .pSubpasses = (VkSubpassDescription []) {
-                                           {
-                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                              .inputAttachmentCount = 0,
-                                              .colorAttachmentCount = 1,
-                                              .pColorAttachments = (VkAttachmentReference []) {
-                                                 {
-                                                    .attachment = 0,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pResolveAttachments = (VkAttachmentReference []) {
-                                                  {
-                                                     .attachment = VK_ATTACHMENT_UNUSED,
-                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
-                                                  }
-                                               },
-                                               .pDepthStencilAttachment = NULL,
-                                            }
-                                         },
-                                         .dependencyCount = 0
-                                      },
-                                      NULL,
-                                      &self->render_pass);
-
-  self->signal_semaphore = signal_semaphore;
-  self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
-  self->vertex_data = NULL;
-
-#ifdef G_ENABLE_DEBUG
-  self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
-  self->texture_pixels = g_quark_from_static_string ("texture-pixels");
-#endif
-
-  return self;
-}
-
-void
-gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
-{
-  g_array_unref (self->render_ops);
-  g_object_unref (self->vulkan);
-  g_object_unref (self->target);
-  cairo_region_destroy (self->clip);
-  vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
-                       self->render_pass,
-                       NULL);
-  if (self->vertex_data)
-    gsk_vulkan_buffer_free (self->vertex_data);
-  if (self->signal_semaphore != VK_NULL_HANDLE)
-    vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
-                        self->signal_semaphore,
-                        NULL);
-  g_array_unref (self->wait_semaphores);
-
-
-  g_slice_free (GskVulkanRenderPass, self);
-}
-
-static gboolean
-font_has_color_glyphs (const PangoFont *font)
-{
-  cairo_scaled_font_t *scaled_font;
-  gboolean has_color = FALSE;
-
-  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
-  if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
-    {
-      FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
-      has_color = (FT_HAS_COLOR (ft_face) != 0);
-      cairo_ft_scaled_font_unlock_face (scaled_font);
-    }
-
-  return has_color;
-}
-
-#define FALLBACK(...) G_STMT_START { \
-  GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
-  goto fallback; \
-}G_STMT_END
-
-static void
-gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
-                                 GskVulkanRender               *render,
-                                 const GskVulkanPushConstants  *constants,
-                                 GskRenderNode                 *node)
-{
-  GskVulkanOp op = {
-    .type = GSK_VULKAN_OP_FALLBACK,
-    .render.node = node
-  };
-  GskVulkanPipelineType pipeline_type;
-
-  switch (gsk_render_node_get_node_type (node))
-    {
-    case GSK_NOT_A_RENDER_NODE:
-      g_assert_not_reached ();
-      return;
-    case GSK_SHADOW_NODE:
-    default:
-      FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
-
-    case GSK_REPEAT_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
-      else
-        FALLBACK ("Repeat nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_REPEAT;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_BLEND_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
-      else
-        FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_BLEND_MODE;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-       return;
-
-    case GSK_CROSS_FADE_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
-      else
-        FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_CROSS_FADE;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_INSET_SHADOW_NODE:
-      if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
-        FALLBACK ("Blur support not implemented for inset shadows\n");
-      else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
-      else
-        FALLBACK ("Inset shadow nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_INSET_SHADOW;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_OUTSET_SHADOW_NODE:
-      if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
-        FALLBACK ("Blur support not implemented for outset shadows\n");
-      else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
-      else
-        FALLBACK ("Outset shadow nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_CAIRO_NODE:
-      if (gsk_cairo_node_peek_surface (node) == NULL)
-        return;
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
-      else
-        FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_SURFACE;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_TEXT_NODE:
-      {
-        const PangoFont *font = gsk_text_node_peek_font (node);
-        const PangoGlyphInfo *glyphs = gsk_text_node_peek_glyphs (node);
-        guint num_glyphs = gsk_text_node_get_num_glyphs (node);
-        int i;
-        guint count;
-        guint texture_index;
-        GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
-
-        if (font_has_color_glyphs (font))
-          {
-            if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
-            else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
-            else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
-            else
-              FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
-            op.type = GSK_VULKAN_OP_COLOR_TEXT;
-          }
-        else
-          {
-            if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-              pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
-            else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-              pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
-            else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-              pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
-            else
-              FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
-            op.type = GSK_VULKAN_OP_TEXT;
-          }
-        op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-
-        op.text.start_glyph = 0;
-        op.text.texture_index = G_MAXUINT;
-        op.text.scale = self->scale_factor;
-
-        for (i = 0, count = 0; i < num_glyphs; i++)
-          {
-            const PangoGlyphInfo *gi = &glyphs[i];
-
-            texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale);
-            if (op.text.texture_index == G_MAXUINT)
-              op.text.texture_index = texture_index;
-            if (texture_index != op.text.texture_index)
-              {
-                op.text.num_glyphs = count;
-
-                g_array_append_val (self->render_ops, op);
-
-                count = 1;
-                op.text.start_glyph = i;
-                op.text.texture_index = texture_index;
-              }
-            else
-              count++;
-          }
-
-        if (op.text.texture_index != G_MAXUINT && count != 0)
-          {
-            op.text.num_glyphs = count;
-            g_array_append_val (self->render_ops, op);
-          }
-
-        return;
-      }
-
-    case GSK_TEXTURE_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
-      else
-        FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_TEXTURE;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_COLOR_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
-      else
-        FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_COLOR;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_LINEAR_GRADIENT_NODE:
-    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
-      if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
-        FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u\n",
-                  gsk_linear_gradient_node_get_n_color_stops (node),
-                  GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
-      else
-        FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_OPACITY_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
-      else
-        FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_OPACITY;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_BLUR_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
-      else
-        FALLBACK ("Blur nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_BLUR;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_COLOR_MATRIX_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
-      else
-        FALLBACK ("Color matrix nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_COLOR_MATRIX;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_BORDER_NODE:
-      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
-        pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
-        pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
-      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
-        pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
-      else
-        FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
-      op.type = GSK_VULKAN_OP_BORDER;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-      g_array_append_val (self->render_ops, op);
-      return;
-
-    case GSK_CONTAINER_NODE:
-      {
-        guint i;
-
-        for (i = 0; i < gsk_container_node_get_n_children (node); i++)
-          {
-            gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
-          }
-      }
-      return;
-
-    case GSK_TRANSFORM_NODE:
-      {
-        graphene_matrix_t transform, mv;
-        GskRenderNode *child;
-
-#if 0
-       if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
-          FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
-#endif
-
-        graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
-        graphene_matrix_init_from_matrix (&mv, &self->mv);
-        graphene_matrix_multiply (&transform, &mv, &self->mv);
-        child = gsk_transform_node_get_child (node);
-        if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
-          FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
-        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
-        g_array_append_val (self->render_ops, op);
-
-        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
-        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
-        graphene_matrix_init_from_matrix (&self->mv, &mv);
-        g_array_append_val (self->render_ops, op);
-      }
-      return;
-
-    case GSK_CLIP_NODE:
-      {
-        if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
-          FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
-        if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
-          return;
-
-        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
-        g_array_append_val (self->render_ops, op);
-
-        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
-
-        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
-        g_array_append_val (self->render_ops, op);
-      }
-      return;
-
-    case GSK_ROUNDED_CLIP_NODE:
-      {
-        if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
-                                                          constants,
-                                                          gsk_rounded_clip_node_peek_clip (node)))
-          FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
-        if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
-          return;
-
-        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
-        g_array_append_val (self->render_ops, op);
-
-        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
-
-        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
-        g_array_append_val (self->render_ops, op);
-      }
-      return;
-    }
-
-  g_assert_not_reached ();
-  return;
-
-fallback:
-  switch (constants->clip.type)
-    {
-      case GSK_VULKAN_CLIP_NONE:
-        op.type = GSK_VULKAN_OP_FALLBACK;
-        break;
-      case GSK_VULKAN_CLIP_RECT:
-        op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
-        gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
-        break;
-      case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
-      case GSK_VULKAN_CLIP_ROUNDED:
-        op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
-        gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
-        break;
-      case GSK_VULKAN_CLIP_ALL_CLIPPED:
-      default:
-        g_assert_not_reached ();
-        return;
-    }
-  op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
-  g_array_append_val (self->render_ops, op);
-}
-#undef FALLBACK
-
-void
-gsk_vulkan_render_pass_add (GskVulkanRenderPass     *self,
-                            GskVulkanRender         *render,
-                            GskRenderNode           *node)
-{
-  GskVulkanOp op = { 0, };
-  graphene_matrix_t mvp;
-
-  graphene_matrix_multiply (&self->mv, &self->p, &mvp);
-  op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
-  gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
-  g_array_append_val (self->render_ops, op);
-
-  gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
-}
-
-static GskVulkanImage *
-gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass   *self,
-                                            GskVulkanRender       *render,
-                                            GskVulkanUploader     *uploader,
-                                            GskRenderNode         *node,
-                                            const graphene_rect_t *bounds,
-                                            GskVulkanClip         *current_clip,
-                                            graphene_rect_t       *tex_rect)
-{
-  GskVulkanImage *result;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-
-  switch ((guint) gsk_render_node_get_node_type (node))
-    {
-    case GSK_TEXTURE_NODE:
-      if (graphene_rect_equal (bounds, &node->bounds))
-        {
-          result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
-                                                          gsk_texture_node_get_texture (node),
-                                                          uploader);
-          gsk_vulkan_render_add_cleanup_image (render, result);
-          *tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-          return result;
-        }
-      break;
-
-    case GSK_CAIRO_NODE:
-      if (graphene_rect_equal (bounds, &node->bounds))
-        {
-          surface = cairo_surface_reference ((cairo_surface_t *)gsk_cairo_node_peek_surface (node));
-          goto got_surface;
-        }
-      break;
-
-    default:
-      {
-        VkSemaphore semaphore;
-        graphene_rect_t view;
-        cairo_region_t *clip;
-        GskVulkanRenderPass *pass;
-        graphene_rect_t clipped;
-
-        if (current_clip)
-          graphene_rect_intersection (&current_clip->rect.bounds, bounds, &clipped);
-        else
-          clipped = *bounds;
-
-        if (clipped.size.width == 0 || clipped.size.height == 0)
-          return NULL;
-
-        graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
-        view.origin.x = floor (view.origin.x);
-        view.origin.y = floor (view.origin.y);
-        view.size.width = ceil (view.size.width);
-        view.size.height = ceil (view.size.height);
-
-        result = gsk_vulkan_image_new_for_texture (self->vulkan,
-                                                   view.size.width,
-                                                   view.size.height);
-
-#ifdef G_ENABLE_DEBUG
-        {
-          GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
-          gsk_profiler_counter_add (profiler,
-                                    self->texture_pixels,
-                                    view.size.width * view.size.height);
-        }
-#endif
-
-        vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
-                           &(VkSemaphoreCreateInfo) {
-                             VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
-                             NULL,
-                             0
-                           },
-                           NULL,
-                           &semaphore);
-
-        g_array_append_val (self->wait_semaphores, semaphore);
-
-        clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
-                                                0, 0,
-                                                gsk_vulkan_image_get_width (result),
-                                                gsk_vulkan_image_get_height (result)
-                                              });
-
-        pass = gsk_vulkan_render_pass_new (self->vulkan,
-                                           result,
-                                           self->scale_factor,
-                                           &self->mv,
-                                           &view,
-                                           clip,
-                                           semaphore);
-
-        cairo_region_destroy (clip);
-
-        gsk_vulkan_render_add_render_pass (render, pass);
-        gsk_vulkan_render_pass_add (pass, render, node);
-        gsk_vulkan_render_add_cleanup_image (render, result);
-
-        /* assuming the unclipped bounds should go to texture coordinates 0..1,
-         * calculate the coordinates for the clipped texture size
-         */
-        tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
-        tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
-        tex_rect->size.width = bounds->size.width/clipped.size.width;
-        tex_rect->size.height = bounds->size.height/clipped.size.height;
-
-        return result;
-      }
-   }
-
-  GSK_NOTE (FALLBACK, g_print ("Node as texture not implemented for this case. Using %gx%g fallback surface\n",
-                               ceil (bounds->size.width),
-                               ceil (bounds->size.height)));
-#ifdef G_ENABLE_DEBUG
-  {
-    GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
-    gsk_profiler_counter_add (profiler,
-                              self->fallback_pixels,
-                              ceil (bounds->size.width) * ceil (bounds->size.height));
-  }
-#endif
-
-  /* XXX: We could intersect bounds with clip bounds here */
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        ceil (bounds->size.width),
-                                        ceil (bounds->size.height));
-  cr = cairo_create (surface);
-  cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
-
-  gsk_render_node_draw (node, cr);
-
-  cairo_destroy (cr);
-
-got_surface:
-  result = gsk_vulkan_image_new_from_data (uploader,
-                                           cairo_image_surface_get_data (surface),
-                                           cairo_image_surface_get_width (surface),
-                                           cairo_image_surface_get_height (surface),
-                                           cairo_image_surface_get_stride (surface));
-
-  cairo_surface_destroy (surface);
-
-  gsk_vulkan_render_add_cleanup_image (render, result);
-
-  tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
-  tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
-  tex_rect->size.width = node->bounds.size.width/bounds->size.width;
-  tex_rect->size.height = node->bounds.size.height/bounds->size.height;
-
-  return result;
-}
-
-static void
-gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass  *self,
-                                        GskVulkanOpRender    *op,
-                                        GskVulkanRender      *render,
-                                        GskVulkanUploader    *uploader)
-{
-  GskRenderNode *node;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-
-  node = op->node;
-
-  GSK_NOTE (FALLBACK,
-            g_print ("Upload op=%s, node %s[%p], bounds %gx%g\n",
-                     op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
-                     (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
-                     node->name ? node->name : node->node_class->type_name, node,
-                     ceil (node->bounds.size.width),
-                     ceil (node->bounds.size.height)));
-#ifdef G_ENABLE_DEBUG
-  {
-    GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
-    gsk_profiler_counter_add (profiler,
-                              self->fallback_pixels,
-                              ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
-  }
-#endif
-
-  /* XXX: We could intersect bounds with clip bounds here */
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        ceil (node->bounds.size.width * self->scale_factor),
-                                        ceil (node->bounds.size.height * self->scale_factor));
-  cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
-  cr = cairo_create (surface);
-  cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
-
-  if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
-    {
-      cairo_rectangle (cr,
-                       op->clip.bounds.origin.x, op->clip.bounds.origin.y,
-                       op->clip.bounds.size.width, op->clip.bounds.size.height);
-      cairo_clip (cr);
-    }
-  else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
-    {
-      gsk_rounded_rect_path (&op->clip, cr);
-      cairo_clip (cr);
-    }
-  else
-    {
-      g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
-    }
-
-  gsk_render_node_draw (node, cr);
-
-  cairo_destroy (cr);
-
-  op->source = gsk_vulkan_image_new_from_data (uploader,
-                                               cairo_image_surface_get_data (surface),
-                                               cairo_image_surface_get_width (surface),
-                                               cairo_image_surface_get_height (surface),
-                                               cairo_image_surface_get_stride (surface));
-
-  op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-
-  cairo_surface_destroy (surface);
-
-  gsk_vulkan_render_add_cleanup_image (render, op->source);
-}
-
-void
-gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
-                               GskVulkanRender      *render,
-                               GskVulkanUploader    *uploader)
-{
-  GskVulkanOp *op;
-  guint i;
-  GskVulkanClip *clip = NULL;
-
-  for (i = 0; i < self->render_ops->len; i++)
-    {
-      op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
-      switch (op->type)
-        {
-        case GSK_VULKAN_OP_FALLBACK:
-        case GSK_VULKAN_OP_FALLBACK_CLIP:
-        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
-          gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
-          break;
-
-        case GSK_VULKAN_OP_SURFACE:
-          {
-            cairo_surface_t *surface;
-
-            surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (op->render.node);
-            op->render.source = gsk_vulkan_image_new_from_data (uploader,
-                                                                cairo_image_surface_get_data (surface),
-                                                                cairo_image_surface_get_width (surface),
-                                                                cairo_image_surface_get_height (surface),
-                                                                cairo_image_surface_get_stride (surface));
-            op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-
-            gsk_vulkan_render_add_cleanup_image (render, op->render.source);
-          }
-          break;
-
-        case GSK_VULKAN_OP_TEXT:
-        case GSK_VULKAN_OP_COLOR_TEXT:
-          {
-            op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
-                                                                   uploader,
-                                                                   op->text.texture_index);
-            gsk_vulkan_render_add_cleanup_image (render, op->text.source);
-          }
-          break;
-
-        case GSK_VULKAN_OP_TEXTURE:
-          {
-            op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
-                                                                       gsk_texture_node_get_texture (op->render.node),
-                                                                       uploader);
-            op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-            gsk_vulkan_render_add_cleanup_image (render, op->render.source);
-          }
-          break;
-
-        case GSK_VULKAN_OP_OPACITY:
-          {
-            GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            child,
-                                                                            &child->bounds,
-                                                                            clip,
-                                                                            &op->render.source_rect);
-          }
-          break;
-
-        case GSK_VULKAN_OP_REPEAT:
-          {
-            GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
-            const graphene_rect_t *bounds = &op->render.node->bounds;
-            const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (op->render.node);
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            child,
-                                                                            child_bounds,
-                                                                            NULL,
-                                                                            &op->render.source_rect);
-
-            op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
-            op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
-            op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
-            op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
-          }
-          break;
-
-        case GSK_VULKAN_OP_BLUR:
-          {
-            GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            child,
-                                                                            &child->bounds,
-                                                                            clip,
-                                                                            &op->render.source_rect);
-          }
-          break;
-
-        case GSK_VULKAN_OP_COLOR_MATRIX:
-          {
-            GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            child,
-                                                                            &child->bounds,
-                                                                            clip,
-                                                                            &op->render.source_rect);
-          }
-          break;
-
-        case GSK_VULKAN_OP_CROSS_FADE:
-          {
-            GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
-            GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
-            const graphene_rect_t *bounds = &op->render.node->bounds;
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            start,
-                                                                            &start->bounds,
-                                                                            clip,
-                                                                            &op->render.source_rect);
-            op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
-            op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
-            op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
-            op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
-
-            op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                             render,
-                                                                             uploader,
-                                                                             end,
-                                                                             &end->bounds,
-                                                                             clip,
-                                                                             &op->render.source2_rect);
-            op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
-            op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
-            op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
-            op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
-          }
-          break;
-
-        case GSK_VULKAN_OP_BLEND_MODE:
-          {
-            GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
-            GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
-            const graphene_rect_t *bounds = &op->render.node->bounds;
-
-            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                            render,
-                                                                            uploader,
-                                                                            top,
-                                                                            &top->bounds,
-                                                                            clip,
-                                                                            &op->render.source_rect);
-            op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
-            op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
-            op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
-            op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
-
-            op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
-                                                                             render,
-                                                                             uploader,
-                                                                             bottom,
-                                                                             &bottom->bounds,
-                                                                             clip,
-                                                                             &op->render.source2_rect);
-            op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
-            op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
-            op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
-            op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
-          }
-          break;
-
-        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
-          clip = &op->constants.constants.clip;
-          break;
-
-        default:
-          g_assert_not_reached ();
-        case GSK_VULKAN_OP_COLOR:
-        case GSK_VULKAN_OP_LINEAR_GRADIENT:
-        case GSK_VULKAN_OP_BORDER:
-        case GSK_VULKAN_OP_INSET_SHADOW:
-        case GSK_VULKAN_OP_OUTSET_SHADOW:
-          break;
-        }
-    }
-}
-
-static gsize
-gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
-{
-  GskVulkanOp *op;
-  gsize n_bytes;
-  guint i;
-
-  n_bytes = 0;
-  for (i = 0; i < self->render_ops->len; i++)
-    {
-      op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
-      switch (op->type)
-        {
-        case GSK_VULKAN_OP_FALLBACK:
-        case GSK_VULKAN_OP_FALLBACK_CLIP:
-        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
-        case GSK_VULKAN_OP_SURFACE:
-        case GSK_VULKAN_OP_TEXTURE:
-        case GSK_VULKAN_OP_REPEAT:
-          op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_TEXT:
-          op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
-                                                                              op->text.num_glyphs);
-          n_bytes += op->text.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_COLOR_TEXT:
-          op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
-                                                                                    op->text.num_glyphs);
-          n_bytes += op->text.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_COLOR:
-          op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_LINEAR_GRADIENT:
-          op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_OPACITY:
-        case GSK_VULKAN_OP_COLOR_MATRIX:
-          op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_BLUR:
-          op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_BORDER:
-          op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_INSET_SHADOW:
-        case GSK_VULKAN_OP_OUTSET_SHADOW:
-          op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_CROSS_FADE:
-          op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        case GSK_VULKAN_OP_BLEND_MODE:
-          op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
-          n_bytes += op->render.vertex_count;
-          break;
-
-        default:
-          g_assert_not_reached ();
-
-        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
-          continue;
-        }
-    }
-
-  return n_bytes;
-}
-
-static gsize
-gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
-                                            GskVulkanRender     *render,
-                                            guchar              *data,
-                                            gsize                offset,
-                                            gsize                total)
-{
-  GskVulkanOp *op;
-  gsize n_bytes;
-  guint i;
-
-  n_bytes = 0;
-  for (i = 0; i < self->render_ops->len; i++)
-    {
-      op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
-      switch (op->type)
-        {
-        case GSK_VULKAN_OP_FALLBACK:
-        case GSK_VULKAN_OP_FALLBACK_CLIP:
-        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
-        case GSK_VULKAN_OP_SURFACE:
-        case GSK_VULKAN_OP_TEXTURE:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
-                                                             data + n_bytes + offset,
-                                                             &op->render.node->bounds,
-                                                             &op->render.source_rect);
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_REPEAT:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
-                                                             data + n_bytes + offset,
-                                                             &op->render.node->bounds,
-                                                             &op->render.source_rect);
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_TEXT:
-          {
-            op->text.vertex_offset = offset + n_bytes;
-            gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
-                                                          data + n_bytes + offset,
-                                                          GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
-                                                          &op->text.node->bounds,
-                                                          (PangoFont *)gsk_text_node_peek_font (op->text.node),
-                                                          gsk_text_node_get_num_glyphs (op->text.node),
-                                                          gsk_text_node_peek_glyphs (op->text.node),
-                                                          gsk_text_node_peek_color (op->text.node),
-                                                          gsk_text_node_get_x (op->text.node),
-                                                          gsk_text_node_get_y (op->text.node),
-                                                          op->text.start_glyph,
-                                                          op->text.num_glyphs,
-                                                          op->text.scale);
-            n_bytes += op->text.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_COLOR_TEXT:
-          {
-            op->text.vertex_offset = offset + n_bytes;
-            gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
-                                                                data + n_bytes + offset,
-                                                                GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
-                                                                &op->text.node->bounds,
-                                                                (PangoFont *)gsk_text_node_peek_font (op->text.node),
-                                                                gsk_text_node_get_num_glyphs (op->text.node),
-                                                                gsk_text_node_peek_glyphs (op->text.node),
-                                                                gsk_text_node_get_x (op->text.node),
-                                                                gsk_text_node_get_y (op->text.node),
-                                                                op->text.start_glyph,
-                                                                op->text.num_glyphs,
-                                                                op->text.scale);
-            n_bytes += op->text.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_COLOR:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
-                                                           data + n_bytes + offset,
-                                                           &op->render.node->bounds,
-                                                           gsk_color_node_peek_color (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_LINEAR_GRADIENT:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
-                                                                     data + n_bytes + offset,
-                                                                     &op->render.node->bounds,
-                                                                     gsk_linear_gradient_node_peek_start (op->render.node),
-                                                                     gsk_linear_gradient_node_peek_end (op->render.node),
-                                                                     gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
-                                                                     gsk_linear_gradient_node_get_n_color_stops (op->render.node),
-                                                                     gsk_linear_gradient_node_peek_color_stops (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_OPACITY:
-          {
-            graphene_matrix_t color_matrix;
-            graphene_vec4_t color_offset;
-
-            graphene_matrix_init_from_float (&color_matrix,
-                                             (float[16]) {
-                                                 1.0, 0.0, 0.0, 0.0,
-                                                 0.0, 1.0, 0.0, 0.0,
-                                                 0.0, 0.0, 1.0, 0.0,
-                                                 0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
-                                             });
-            graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
-            op->render.vertex_offset = offset + n_bytes;
-
-            gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
-                                                            data + n_bytes + offset,
-                                                            &op->render.node->bounds,
-                                                            &op->render.source_rect,
-                                                            &color_matrix,
-                                                            &color_offset);
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_BLUR:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
-                                                          data + n_bytes + offset,
-                                                          &op->render.node->bounds,
-                                                          &op->render.source_rect,
-                                                          gsk_blur_node_get_radius (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_COLOR_MATRIX:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
-                                                            data + n_bytes + offset,
-                                                            &op->render.node->bounds,
-                                                            &op->render.source_rect,
-                                                            gsk_color_matrix_node_peek_color_matrix (op->render.node),
-                                                            gsk_color_matrix_node_peek_color_offset (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_BORDER:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
-                                                            data + n_bytes + offset,
-                                                            gsk_border_node_peek_outline (op->render.node),
-                                                            gsk_border_node_peek_widths (op->render.node),
-                                                            gsk_border_node_peek_colors (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_INSET_SHADOW:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
-                                                                data + n_bytes + offset,
-                                                                gsk_inset_shadow_node_peek_outline (op->render.node),
-                                                                gsk_inset_shadow_node_peek_color (op->render.node),
-                                                                gsk_inset_shadow_node_get_dx (op->render.node),
-                                                                gsk_inset_shadow_node_get_dy (op->render.node),
-                                                                gsk_inset_shadow_node_get_spread (op->render.node),
-                                                                gsk_inset_shadow_node_get_blur_radius (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_OUTSET_SHADOW:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
-                                                                data + n_bytes + offset,
-                                                                gsk_outset_shadow_node_peek_outline (op->render.node),
-                                                                gsk_outset_shadow_node_peek_color (op->render.node),
-                                                                gsk_outset_shadow_node_get_dx (op->render.node),
-                                                                gsk_outset_shadow_node_get_dy (op->render.node),
-                                                                gsk_outset_shadow_node_get_spread (op->render.node),
-                                                                gsk_outset_shadow_node_get_blur_radius (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_CROSS_FADE:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
-                                                                data + n_bytes + offset,
-                                                                &op->render.node->bounds,
-                                                                &op->render.source_rect,
-                                                                &op->render.source2_rect,
-                                                                gsk_cross_fade_node_get_progress (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        case GSK_VULKAN_OP_BLEND_MODE:
-          {
-            op->render.vertex_offset = offset + n_bytes;
-            gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
-                                                                data + n_bytes + offset,
-                                                                &op->render.node->bounds,
-                                                                &op->render.source_rect,
-                                                                &op->render.source2_rect,
-                                                                gsk_blend_node_get_blend_mode (op->render.node));
-            n_bytes += op->render.vertex_count;
-          }
-          break;
-
-        default:
-          g_assert_not_reached ();
-        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
-          continue;
-        }
-
-      g_assert (n_bytes + offset <= total);
-    }
-
-  return n_bytes;
-}
-
-static GskVulkanBuffer *
-gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
-                                        GskVulkanRender     *render)
-{
-  if (self->vertex_data == NULL)
-    {
-      gsize n_bytes;
-      guchar *data;
-
-      n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
-      self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
-      data = gsk_vulkan_buffer_map (self->vertex_data);
-      gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
-      gsk_vulkan_buffer_unmap (self->vertex_data);
-    }
-
-  return self->vertex_data;
-}
-
-gsize
-gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass  *self,
-                                            VkSemaphore         **semaphores)
-{
-  *semaphores = (VkSemaphore *)self->wait_semaphores->data;
-  return self->wait_semaphores->len;
-}
-
-gsize
-gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass  *self,
-                                              VkSemaphore         **semaphores)
-{
-  *semaphores = (VkSemaphore *)&self->signal_semaphore;
-  return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
-}
-
-void
-gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
-                                                GskVulkanRender     *render)
-{
-  GskVulkanOp *op;
-  guint i;
-
-  for (i = 0; i < self->render_ops->len; i++)
-    {
-      op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
-      switch (op->type)
-        {
-        case GSK_VULKAN_OP_FALLBACK:
-        case GSK_VULKAN_OP_FALLBACK_CLIP:
-        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
-        case GSK_VULKAN_OP_SURFACE:
-        case GSK_VULKAN_OP_TEXTURE:
-        case GSK_VULKAN_OP_OPACITY:
-        case GSK_VULKAN_OP_BLUR:
-        case GSK_VULKAN_OP_COLOR_MATRIX:
-          if (op->render.source)
-            op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
-          break;
-
-        case GSK_VULKAN_OP_REPEAT:
-          if (op->render.source)
-            op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
-          break;
-
-        case GSK_VULKAN_OP_TEXT:
-        case GSK_VULKAN_OP_COLOR_TEXT:
-          op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
-          break;
-
-        case GSK_VULKAN_OP_CROSS_FADE:
-        case GSK_VULKAN_OP_BLEND_MODE:
-          if (op->render.source && op->render.source2)
-            {
-              op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
-              op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
-            }
-          break;
-
-        default:
-          g_assert_not_reached ();
-
-        case GSK_VULKAN_OP_COLOR:
-        case GSK_VULKAN_OP_LINEAR_GRADIENT:
-        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
-        case GSK_VULKAN_OP_BORDER:
-        case GSK_VULKAN_OP_INSET_SHADOW:
-        case GSK_VULKAN_OP_OUTSET_SHADOW:
-          break;
-        }
-    }
-}
-
-static void
-gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass     *self,
-                                  GskVulkanRender         *render,
-                                  guint                    layout_count,
-                                  VkPipelineLayout        *pipeline_layout,
-                                  VkCommandBuffer          command_buffer)
-{
-  GskVulkanPipeline *current_pipeline = NULL;
-  gsize current_draw_index = 0;
-  GskVulkanOp *op;
-  guint i, step;
-  GskVulkanBuffer *vertex_buffer;
-
-  vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
-
-  for (i = 0; i < self->render_ops->len; i += step)
-    {
-      op = &g_array_index (self->render_ops, GskVulkanOp, i);
-      step = 1;
-
-      switch (op->type)
-        {
-        case GSK_VULKAN_OP_FALLBACK:
-        case GSK_VULKAN_OP_FALLBACK_CLIP:
-        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
-        case GSK_VULKAN_OP_SURFACE:
-        case GSK_VULKAN_OP_TEXTURE:
-        case GSK_VULKAN_OP_REPEAT:
-          if (!op->render.source)
-            continue;
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   1,
-                                   (VkDescriptorSet[1]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
-                                                                  command_buffer,
-                                                                  current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_TEXT:
-          if (current_pipeline != op->text.pipeline)
-            {
-              current_pipeline = op->text.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->text.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   1,
-                                   (VkDescriptorSet[1]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
-                                                               command_buffer,
-                                                               current_draw_index, op->text.num_glyphs);
-          break;
-
-        case GSK_VULKAN_OP_COLOR_TEXT:
-          if (current_pipeline != op->text.pipeline)
-            {
-              current_pipeline = op->text.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->text.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   1,
-                                   (VkDescriptorSet[1]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
-                                                                     command_buffer,
-                                                                     current_draw_index, op->text.num_glyphs);
-          break;
-
-        case GSK_VULKAN_OP_OPACITY:
-        case GSK_VULKAN_OP_COLOR_MATRIX:
-          if (!op->render.source)
-            continue;
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   1,
-                                   (VkDescriptorSet[1]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
-                                                                 command_buffer,
-                                                                 current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_BLUR:
-          if (!op->render.source)
-            continue;
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   1,
-                                   (VkDescriptorSet[1]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
-                                                               command_buffer,
-                                                               current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_COLOR:
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          for (step = 1; step + i < self->render_ops->len; step++)
-            {
-              GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
-              if (cmp->type != GSK_VULKAN_OP_COLOR || 
-                  cmp->render.pipeline != current_pipeline)
-                break;
-            }
-          current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
-                                                                command_buffer,
-                                                                current_draw_index, step);
-          break;
-
-        case GSK_VULKAN_OP_LINEAR_GRADIENT:
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-          current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
-                                                                          command_buffer,
-                                                                          current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_BORDER:
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-          current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
-                                                                 command_buffer,
-                                                                 current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_INSET_SHADOW:
-        case GSK_VULKAN_OP_OUTSET_SHADOW:
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-          current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
-                                                                     command_buffer,
-                                                                     current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
-          for (int i = 0; i < layout_count; i++)
-            gsk_vulkan_push_constants_push (&op->constants.constants,
-                                            command_buffer,
-                                            pipeline_layout[i]);
-          break;
-
-        case GSK_VULKAN_OP_CROSS_FADE:
-          if (!op->render.source || !op->render.source2)
-            continue;
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   2,
-                                   (VkDescriptorSet[2]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
-                                                                     command_buffer,
-                                                                     current_draw_index, 1);
-          break;
-
-        case GSK_VULKAN_OP_BLEND_MODE:
-          if (!op->render.source || !op->render.source2)
-            continue;
-          if (current_pipeline != op->render.pipeline)
-            {
-              current_pipeline = op->render.pipeline;
-              vkCmdBindPipeline (command_buffer,
-                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
-              vkCmdBindVertexBuffers (command_buffer,
-                                      0,
-                                      1,
-                                      (VkBuffer[1]) {
-                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
-                                      },
-                                      (VkDeviceSize[1]) { op->render.vertex_offset });
-              current_draw_index = 0;
-            }
-
-          vkCmdBindDescriptorSets (command_buffer,
-                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
-                                   0,
-                                   2,
-                                   (VkDescriptorSet[2]) {
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
-                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
-                                   },
-                                   0,
-                                   NULL);
-
-          current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
-                                                                     command_buffer,
-                                                                     current_draw_index, 1);
-          break;
-
-        default:
-          g_assert_not_reached ();
-          break;
-        }
-    }
-}
-
-void
-gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
-                             GskVulkanRender         *render,
-                             guint                    layout_count,
-                             VkPipelineLayout        *pipeline_layout,
-                             VkCommandBuffer          command_buffer)
-{
-  guint i;
-
-  vkCmdSetViewport (command_buffer,
-                    0,
-                    1,
-                    &(VkViewport) {
-                        .x = 0,
-                        .y = 0,
-                        .width = self->viewport.size.width,
-                        .height = self->viewport.size.height,
-                        .minDepth = 0,
-                        .maxDepth = 1
-                    });
-
-  for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
-    {
-      cairo_rectangle_int_t rect;
-
-      cairo_region_get_rectangle (self->clip, i, &rect);
-
-      vkCmdSetScissor (command_buffer,
-                       0,
-                       1,
-                       &(VkRect2D) {
-                          { rect.x * self->scale_factor, rect.y * self->scale_factor },
-                          { rect.width * self->scale_factor, rect.height * self->scale_factor }
-                       });
-
-      vkCmdBeginRenderPass (command_buffer,
-                            &(VkRenderPassBeginInfo) {
-                                .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                                .renderPass = self->render_pass,
-                                .framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
-                                .renderArea = { 
-                                    { rect.x * self->scale_factor, rect.y * self->scale_factor },
-                                    { rect.width * self->scale_factor, rect.height * self->scale_factor }
-                                },
-                                .clearValueCount = 1,
-                                .pClearValues = (VkClearValue [1]) {
-                                    { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
-                                }
-                            },
-                            VK_SUBPASS_CONTENTS_INLINE);
-
-      gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
-
-      vkCmdEndRenderPass (command_buffer);
-    }
-}
diff --git a/gsk/gskvulkanrenderpassprivate.h b/gsk/gskvulkanrenderpassprivate.h
deleted file mode 100644 (file)
index 4ec8f4e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
-#define __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <gsk/gskrendernode.h>
-
-#include "gsk/gskvulkanbufferprivate.h"
-#include "gsk/gskvulkanrenderprivate.h"
-#include "gsk/gskprivate.h"
-
-G_BEGIN_DECLS
-
-
-GskVulkanRenderPass *   gsk_vulkan_render_pass_new                      (GdkVulkanContext       *context,
-                                                                         GskVulkanImage         *target,
-                                                                         int                     scale_factor,
-                                                                         graphene_matrix_t      *mv,
-                                                                         graphene_rect_t        *viewport,
-                                                                         cairo_region_t         *clip,
-                                                                         VkSemaphore             signal_semaphore);
-
-void                    gsk_vulkan_render_pass_free                     (GskVulkanRenderPass    *self);
-
-void                    gsk_vulkan_render_pass_add                      (GskVulkanRenderPass    *self,
-                                                                         GskVulkanRender        *render,
-                                                                         GskRenderNode          *node);
-
-void                    gsk_vulkan_render_pass_upload                   (GskVulkanRenderPass    *self,
-                                                                         GskVulkanRender        *render,
-                                                                         GskVulkanUploader      *uploader);
-void                    gsk_vulkan_render_pass_reserve_descriptor_sets  (GskVulkanRenderPass    *self,
-                                                                         GskVulkanRender        *render);
-void                    gsk_vulkan_render_pass_draw                     (GskVulkanRenderPass    *self,
-                                                                         GskVulkanRender        *render,
-                                                                         guint                   layout_count,
-                                                                         VkPipelineLayout       *pipeline_layout,
-                                                                         VkCommandBuffer         command_buffer);
-gsize                   gsk_vulkan_render_pass_get_wait_semaphores      (GskVulkanRenderPass    *self,
-                                                                         VkSemaphore           **semaphores);
-gsize                   gsk_vulkan_render_pass_get_signal_semaphores    (GskVulkanRenderPass    *self,
-                                                                         VkSemaphore           **semaphores);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDER_PASS_PRIVATE_H__ */
diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h
deleted file mode 100644 (file)
index eb0b688..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef __GSK_VULKAN_RENDER_PRIVATE_H__
-#define __GSK_VULKAN_RENDER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <gsk/gskrendernode.h>
-
-#include "gsk/gskvulkanimageprivate.h"
-#include "gsk/gskvulkanpipelineprivate.h"
-#include "gsk/gskvulkanrenderpassprivate.h"
-#include "gsk/gskprivate.h"
-
-G_BEGIN_DECLS
-
-typedef enum {
-  GSK_VULKAN_PIPELINE_TEXTURE,
-  GSK_VULKAN_PIPELINE_TEXTURE_CLIP,
-  GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_COLOR,
-  GSK_VULKAN_PIPELINE_COLOR_CLIP,
-  GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT,
-  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP,
-  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_COLOR_MATRIX,
-  GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
-  GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_BORDER,
-  GSK_VULKAN_PIPELINE_BORDER_CLIP,
-  GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_INSET_SHADOW,
-  GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP,
-  GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_OUTSET_SHADOW,
-  GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP,
-  GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_BLUR,
-  GSK_VULKAN_PIPELINE_BLUR_CLIP,
-  GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_TEXT,
-  GSK_VULKAN_PIPELINE_TEXT_CLIP,
-  GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_COLOR_TEXT,
-  GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
-  GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_CROSS_FADE,
-  GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP,
-  GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED,
-  GSK_VULKAN_PIPELINE_BLEND_MODE,
-  GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP,
-  GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED,
-  /* add more */
-  GSK_VULKAN_N_PIPELINES
-} GskVulkanPipelineType;
-
-GskVulkanRender *       gsk_vulkan_render_new                           (GskRenderer            *renderer,
-                                                                         GdkVulkanContext       *context);
-void                    gsk_vulkan_render_free                          (GskVulkanRender        *self);
-
-gboolean                gsk_vulkan_render_is_busy                       (GskVulkanRender        *self);
-void                    gsk_vulkan_render_reset                         (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *target,
-                                                                         const graphene_rect_t  *rect);
-
-GskRenderer *           gsk_vulkan_render_get_renderer                  (GskVulkanRender        *self);
-
-void                    gsk_vulkan_render_add_cleanup_image             (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *image);
-
-void                    gsk_vulkan_render_add_node                      (GskVulkanRender        *self,
-                                                                         GskRenderNode          *node);
-
-void                    gsk_vulkan_render_add_render_pass               (GskVulkanRender        *self,
-                                                                         GskVulkanRenderPass    *pass);
-
-void                    gsk_vulkan_render_upload                        (GskVulkanRender        *self);
-
-GskVulkanPipeline *     gsk_vulkan_render_get_pipeline                  (GskVulkanRender        *self,
-                                                                         GskVulkanPipelineType   pipeline_type);
-VkDescriptorSet         gsk_vulkan_render_get_descriptor_set            (GskVulkanRender        *self,
-                                                                         gsize                   id);
-gsize                   gsk_vulkan_render_reserve_descriptor_set        (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *source,
-                                                                         gboolean                repeat);
-void                    gsk_vulkan_render_draw                          (GskVulkanRender        *self);
-
-void                    gsk_vulkan_render_submit                        (GskVulkanRender        *self);
-
-GdkTexture *            gsk_vulkan_render_download_target               (GskVulkanRender        *self);
-VkFramebuffer           gsk_vulkan_render_get_framebuffer               (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *image);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */
diff --git a/gsk/gskvulkanshader.c b/gsk/gskvulkanshader.c
deleted file mode 100644 (file)
index 1010b21..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "config.h"
-
-#include "gskvulkanshaderprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanShader
-{
-  GdkVulkanContext *vulkan;
-
-  GskVulkanShaderType type;
-  VkShaderModule vk_shader;
-};
-
-static GskVulkanShader *
-gsk_vulkan_shader_new_from_bytes (GdkVulkanContext     *context,
-                                  GskVulkanShaderType   type,
-                                  GBytes               *bytes,
-                                  GError              **error)
-{
-  GskVulkanShader *self;
-  VkShaderModule shader;
-  VkResult res;
-
-  res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context),
-                                            &(VkShaderModuleCreateInfo) {
-                                                .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
-                                                .codeSize = g_bytes_get_size (bytes),
-                                                .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
-                                            },
-                                            NULL,
-                                            &shader);
-  if (res != VK_SUCCESS)
-    {
-      /* Someone invent better error categories plz */
-      g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
-                   "Could not create shader: %s", gdk_vulkan_strerror (res));
-      return NULL;
-    }
-
-  self = g_slice_new0 (GskVulkanShader);
-
-  self->vulkan = g_object_ref (context);
-  self->type = type;
-  self->vk_shader = shader;
-
-  return self;
-}
-
-GskVulkanShader *
-gsk_vulkan_shader_new_from_resource (GdkVulkanContext     *context,
-                                     GskVulkanShaderType   type,
-                                     const char           *resource_name,
-                                     GError              **error)
-{
-  GskVulkanShader *self;
-  GBytes *bytes;
-  GError *local_error = NULL;
-  char *path;
-
-  path = g_strconcat ("/org/gtk/libgsk/vulkan/",
-                      resource_name, 
-                      type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv",
-                      NULL);
-  bytes = g_resources_lookup_data (path, 0, &local_error);
-  g_free (path);
-  if (bytes == NULL)
-    {
-      GSK_NOTE (VULKAN, g_printerr ("Error loading shader data: %s\n", local_error->message));
-      g_propagate_error (error, local_error);
-      return NULL;
-    }
-
-  self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error);
-  g_bytes_unref (bytes);
-
-  return self;
-}
-
-void
-gsk_vulkan_shader_free (GskVulkanShader *self)
-{
-  vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan),
-                         self->vk_shader,
-                         NULL);
-
-  g_object_unref (self->vulkan);
-
-  g_slice_free (GskVulkanShader, self);
-}
-
-GskVulkanShaderType
-gsk_vulkan_shader_get_type (GskVulkanShader *shader)
-{
-  return shader->type;
-}
-
-VkShaderModule
-gsk_vulkan_shader_get_module (GskVulkanShader *shader)
-{
-  return shader->vk_shader;
-}
-
diff --git a/gsk/gskvulkanshaderprivate.h b/gsk/gskvulkanshaderprivate.h
deleted file mode 100644 (file)
index e94424f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__
-#define __GSK_VULKAN_SHADER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
-  GSK_VULKAN_SHADER_VERTEX,
-  GSK_VULKAN_SHADER_FRAGMENT
-} GskVulkanShaderType;
-
-typedef struct _GskVulkanShader GskVulkanShader;
-
-#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \
-  (VkPipelineShaderStageCreateInfo) { \
-  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
-  .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \
-  .module = gsk_vulkan_shader_get_module (shader), \
-  .pName = "main", \
-}
-
-GskVulkanShader *       gsk_vulkan_shader_new_from_resource             (GdkVulkanContext       *context,
-                                                                         GskVulkanShaderType     type,
-                                                                         const char             *resource_name,
-                                                                         GError                **error);
-void                    gsk_vulkan_shader_free                          (GskVulkanShader        *shader);
-
-GskVulkanShaderType     gsk_vulkan_shader_get_type                      (GskVulkanShader        *shader);
-VkShaderModule          gsk_vulkan_shader_get_module                    (GskVulkanShader        *shader);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_SHADER_PRIVATE_H__ */
diff --git a/gsk/gskvulkantextpipeline.c b/gsk/gskvulkantextpipeline.c
deleted file mode 100644 (file)
index 361c536..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "config.h"
-
-#include "gskvulkantextpipelineprivate.h"
-
-struct _GskVulkanTextPipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
-
-struct _GskVulkanTextInstance
-{
-  float rect[4];
-  float tex_rect[4];
-  float color[4];
-};
-
-G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanTextInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
-      },
-      {
-          .location = 2,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_text_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanTextPipeline *self = GSK_VULKAN_TEXT_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_text_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_text_pipeline_class_init (GskVulkanTextPipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_text_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_text_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_text_pipeline_init (GskVulkanTextPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_text_pipeline_new (GdkVulkanContext        *context,
-                              VkPipelineLayout         layout,
-                              const char              *shader_name,
-                              VkRenderPass             render_pass)
-{
-  return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, layout, shader_name, render_pass,
-                                       VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-gsize
-gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
-                                            int                    num_instances)
-{
-  return sizeof (GskVulkanTextInstance) * num_instances;
-}
-
-void
-gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline  *pipeline,
-                                              guchar                 *data,
-                                              GskVulkanRenderer      *renderer,
-                                              const graphene_rect_t  *rect,
-                                              PangoFont              *font,
-                                              guint                   total_glyphs,
-                                              const PangoGlyphInfo   *glyphs,
-                                              const GdkRGBA          *color,
-                                              float                   x,
-                                              float                   y,
-                                              guint                   start_glyph,
-                                              guint                   num_glyphs,
-                                              float                   scale)
-{
-  GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
-  int i;
-  int count = 0;
-  int x_position = 0;
-
-  for (i = 0; i < start_glyph; i++)
-    x_position += glyphs[i].geometry.width;
-
-  for (; i < total_glyphs && count < num_glyphs; i++)
-    {
-      const PangoGlyphInfo *gi = &glyphs[i];
-
-      if (gi->glyph != PANGO_GLYPH_EMPTY)
-        {
-          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
-          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
-          GskVulkanTextInstance *instance = &instances[count];
-          GskVulkanCachedGlyph *glyph;
-
-          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
-
-          instance->tex_rect[0] = glyph->tx;
-          instance->tex_rect[1] = glyph->ty;
-          instance->tex_rect[2] = glyph->tw;
-          instance->tex_rect[3] = glyph->th;
-
-          instance->rect[0] = x + cx + glyph->draw_x;
-          instance->rect[1] = y + cy + glyph->draw_y;
-          instance->rect[2] = glyph->draw_width;
-          instance->rect[3] = glyph->draw_height;
-
-          instance->color[0] = color->red;
-          instance->color[1] = color->green;
-          instance->color[2] = color->blue;
-          instance->color[3] = color->alpha;
-
-          count++;
-        }
-      x_position += gi->geometry.width;
-    }
-}
-
-gsize
-gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
-                               VkCommandBuffer        command_buffer,
-                               gsize                  offset,
-                               gsize                  n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkantextpipelineprivate.h b/gsk/gskvulkantextpipelineprivate.h
deleted file mode 100644 (file)
index 47517de..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrendererprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanTextPipelineLayout GskVulkanTextPipelineLayout;
-
-#define GSK_TYPE_VULKAN_TEXT_PIPELINE (gsk_vulkan_text_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK, VULKAN_TEXT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_text_pipeline_new                   (GdkVulkanContext              *context,
-                                                                        VkPipelineLayout               layout,
-                                                                        const char                    *shader_name,
-                                                                        VkRenderPass                   render_pass);
-
-gsize                   gsk_vulkan_text_pipeline_count_vertex_data     (GskVulkanTextPipeline         *pipeline,
-                                                                        int                            num_instances);
-void                    gsk_vulkan_text_pipeline_collect_vertex_data   (GskVulkanTextPipeline         *pipeline,
-                                                                        guchar                         *data,
-                                                                        GskVulkanRenderer              *renderer,
-                                                                        const graphene_rect_t          *rect,
-                                                                        PangoFont                      *font,
-                                                                        guint                           total_glyphs,
-                                                                        const PangoGlyphInfo           *glyphs,
-                                                                        const GdkRGBA                  *color,
-                                                                        float                           x,
-                                                                        float                           y,
-                                                                        guint                           start_glyph,
-                                                                        guint                           num_glyphs,
-                                                                        float                           scale);
-gsize                   gsk_vulkan_text_pipeline_draw                  (GskVulkanTextPipeline         *pipeline,
-                                                                        VkCommandBuffer                 command_buffer,
-                                                                        gsize                           offset,
-                                                                        gsize                           n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkantexturepipeline.c b/gsk/gskvulkantexturepipeline.c
deleted file mode 100644 (file)
index 9db7190..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "config.h"
-
-#include "gskvulkantexturepipelineprivate.h"
-
-struct _GskVulkanTexturePipeline
-{
-  GObject parent_instance;
-};
-
-typedef struct _GskVulkanTextureInstance GskVulkanTextureInstance;
-
-struct _GskVulkanTextureInstance
-{
-  float rect[4];
-  float tex_rect[4];
-};
-
-G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
-  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
-      {
-          .binding = 0,
-          .stride = sizeof (GskVulkanTextureInstance),
-          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-      }
-  };
-  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
-      {
-          .location = 0,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, rect),
-      },
-      {
-          .location = 1,
-          .binding = 0,
-          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
-          .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
-      }
-  };
-  static const VkPipelineVertexInputStateCreateInfo info = {
-      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
-      .pVertexBindingDescriptions = vertexBindingDescriptions,
-      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
-      .pVertexAttributeDescriptions = vertexInputAttributeDescription
-  };
-
-  return &info;
-}
-
-static void
-gsk_vulkan_texture_pipeline_finalize (GObject *gobject)
-{
-  //GskVulkanTexturePipeline *self = GSK_VULKAN_TEXTURE_PIPELINE (gobject);
-
-  G_OBJECT_CLASS (gsk_vulkan_texture_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_texture_pipeline_class_init (GskVulkanTexturePipelineClass *klass)
-{
-  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
-  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_texture_pipeline_finalize;
-
-  pipeline_class->get_input_state_create_info = gsk_vulkan_texture_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_texture_pipeline_init (GskVulkanTexturePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
-                                 VkPipelineLayout  layout,
-                                 const char       *shader_name,
-                                 VkRenderPass      render_pass)
-{
-  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXTURE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline)
-{
-  return sizeof (GskVulkanTextureInstance);
-}
-
-void
-gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
-                                                 guchar                   *data,
-                                                 const graphene_rect_t    *rect,
-                                                 const graphene_rect_t    *tex_rect)
-{
-  GskVulkanTextureInstance *instance = (GskVulkanTextureInstance *) data;
-
-  instance->rect[0] = rect->origin.x;
-  instance->rect[1] = rect->origin.y;
-  instance->rect[2] = rect->size.width;
-  instance->rect[3] = rect->size.height;
-  instance->tex_rect[0] = tex_rect->origin.x;
-  instance->tex_rect[1] = tex_rect->origin.y;
-  instance->tex_rect[2] = tex_rect->size.width;
-  instance->tex_rect[3] = tex_rect->size.height;
-}
-
-gsize
-gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
-                                  VkCommandBuffer           command_buffer,
-                                  gsize                     offset,
-                                  gsize                     n_commands)
-{
-  vkCmdDraw (command_buffer,
-             6, n_commands,
-             0, offset);
-
-  return n_commands;
-}
diff --git a/gsk/gskvulkantexturepipelineprivate.h b/gsk/gskvulkantexturepipelineprivate.h
deleted file mode 100644 (file)
index c6435c4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanTexturePipelineLayout GskVulkanTexturePipelineLayout;
-
-#define GSK_TYPE_VULKAN_TEXTURE_PIPELINE (gsk_vulkan_texture_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK, VULKAN_TEXTURE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline *     gsk_vulkan_texture_pipeline_new                 (GdkVulkanContext         *context,
-                                                                         VkPipelineLayout          layout,
-                                                                         const char               *shader_name,
-                                                                         VkRenderPass              render_pass);
-
-gsize                   gsk_vulkan_texture_pipeline_count_vertex_data   (GskVulkanTexturePipeline *pipeline);
-void                    gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
-                                                                         guchar                   *data,
-                                                                         const graphene_rect_t    *rect,
-                                                                         const graphene_rect_t    *tex_rect);
-gsize                   gsk_vulkan_texture_pipeline_draw                (GskVulkanTexturePipeline *pipeline,
-                                                                         VkCommandBuffer           command_buffer,
-                                                                         gsize                     offset,
-                                                                         gsize                     n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__ */
index e110c65e541f66eb89d380c35afb80e0d827d484..b8522376298beb297e5234784950e8498150e76f 100644 (file)
@@ -63,29 +63,29 @@ gsk_private_vulkan_compiled_shaders_deps = []
 
 if have_vulkan
   gsk_private_sources += files([
-    'gskvulkanblendmodepipeline.c',
-    'gskvulkanblurpipeline.c',
-    'gskvulkanborderpipeline.c',
-    'gskvulkanboxshadowpipeline.c',
-    'gskvulkanbuffer.c',
-    'gskvulkanclip.c',
-    'gskvulkancolorpipeline.c',
-    'gskvulkancolortextpipeline.c',
-    'gskvulkancrossfadepipeline.c',
-    'gskvulkancommandpool.c',
-    'gskvulkaneffectpipeline.c',
-    'gskvulkanglyphcache.c',
-    'gskvulkanlineargradientpipeline.c',
-    'gskvulkanimage.c',
-    'gskvulkantextpipeline.c',
-    'gskvulkantexturepipeline.c',
-    'gskvulkanmemory.c',
-    'gskvulkanpipeline.c',
-    'gskvulkanpushconstants.c',
-    'gskvulkanrender.c',
-    'gskvulkanrenderer.c',
-    'gskvulkanrenderpass.c',
-    'gskvulkanshader.c',
+    'vulkan/gskvulkanblendmodepipeline.c',
+    'vulkan/gskvulkanblurpipeline.c',
+    'vulkan/gskvulkanborderpipeline.c',
+    'vulkan/gskvulkanboxshadowpipeline.c',
+    'vulkan/gskvulkanbuffer.c',
+    'vulkan/gskvulkanclip.c',
+    'vulkan/gskvulkancolorpipeline.c',
+    'vulkan/gskvulkancolortextpipeline.c',
+    'vulkan/gskvulkancrossfadepipeline.c',
+    'vulkan/gskvulkancommandpool.c',
+    'vulkan/gskvulkaneffectpipeline.c',
+    'vulkan/gskvulkanglyphcache.c',
+    'vulkan/gskvulkanlineargradientpipeline.c',
+    'vulkan/gskvulkanimage.c',
+    'vulkan/gskvulkantextpipeline.c',
+    'vulkan/gskvulkantexturepipeline.c',
+    'vulkan/gskvulkanmemory.c',
+    'vulkan/gskvulkanpipeline.c',
+    'vulkan/gskvulkanpushconstants.c',
+    'vulkan/gskvulkanrender.c',
+    'vulkan/gskvulkanrenderer.c',
+    'vulkan/gskvulkanrenderpass.c',
+    'vulkan/gskvulkanshader.c',
   ])
 
   subdir('resources/vulkan')
diff --git a/gsk/vulkan/gskvulkanblendmodepipeline.c b/gsk/vulkan/gskvulkanblendmodepipeline.c
new file mode 100644 (file)
index 0000000..117ed41
--- /dev/null
@@ -0,0 +1,146 @@
+#include "config.h"
+
+#include "gskvulkanblendmodepipelineprivate.h"
+
+struct _GskVulkanBlendModePipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
+
+struct _GskVulkanBlendModeInstance
+{
+  float rect[4];
+  float start_tex_rect[4];
+  float end_tex_rect[4];
+  guint32 blend_mode;
+};
+
+G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanBlendModeInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32_UINT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanBlendModePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_blend_mode_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_class_init (GskVulkanBlendModePipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blend_mode_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_blend_mode_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_init (GskVulkanBlendModePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext        *context,
+                                    VkPipelineLayout         layout,
+                                    const char              *shader_name,
+                                    VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline)
+{
+  return sizeof (GskVulkanBlendModeInstance);
+}
+
+void
+gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
+                                                    guchar                *data,
+                                                    const graphene_rect_t *bounds,
+                                                    const graphene_rect_t *start_tex_rect,
+                                                    const graphene_rect_t *end_tex_rect,
+                                                    GskBlendMode blend_mode)
+{
+  GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data;
+
+  instance->rect[0] = bounds->origin.x;
+  instance->rect[1] = bounds->origin.y;
+  instance->rect[2] = bounds->size.width;
+  instance->rect[3] = bounds->size.height;
+
+  instance->start_tex_rect[0] = start_tex_rect->origin.x;
+  instance->start_tex_rect[1] = start_tex_rect->origin.y;
+  instance->start_tex_rect[2] = start_tex_rect->size.width;
+  instance->start_tex_rect[3] = start_tex_rect->size.height;
+
+  instance->end_tex_rect[0] = end_tex_rect->origin.x;
+  instance->end_tex_rect[1] = end_tex_rect->origin.y;
+  instance->end_tex_rect[2] = end_tex_rect->size.width;
+  instance->end_tex_rect[3] = end_tex_rect->size.height;
+
+  instance->blend_mode = blend_mode;
+}
+
+gsize
+gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
+                                     VkCommandBuffer        command_buffer,
+                                     gsize                  offset,
+                                     gsize                  n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkanblendmodepipelineprivate.h b/gsk/vulkan/gskvulkanblendmodepipelineprivate.h
new file mode 100644 (file)
index 0000000..67822e4
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskenums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBlendModePipelineLayout GskVulkanBlendModePipelineLayout;
+
+#define GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE (gsk_vulkan_blend_mode_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK, VULKAN_BLEND_MODE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new                 (GdkVulkanContext           *context,
+                                                                        VkPipelineLayout            layout,
+                                                                        const char                 *shader_name,
+                                                                        VkRenderPass                render_pass);
+
+gsize               gsk_vulkan_blend_mode_pipeline_count_vertex_data   (GskVulkanBlendModePipeline *pipeline);
+void                gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
+                                                                        guchar                     *data,
+                                                                        const graphene_rect_t      *bounds,
+                                                                        const graphene_rect_t      *start_bounds,
+                                                                        const graphene_rect_t      *end_bounds,
+                                                                        GskBlendMode                blend_mode);
+gsize               gsk_vulkan_blend_mode_pipeline_draw                (GskVulkanBlendModePipeline *pipeline,
+                                                                        VkCommandBuffer             command_buffer,
+                                                                        gsize                       offset,
+                                                                        gsize                       n_commands);
+
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanblurpipeline.c b/gsk/vulkan/gskvulkanblurpipeline.c
new file mode 100644 (file)
index 0000000..5686e54
--- /dev/null
@@ -0,0 +1,131 @@
+#include "config.h"
+
+#include "gskvulkanblurpipelineprivate.h"
+
+struct _GskVulkanBlurPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanBlurInstance GskVulkanBlurInstance;
+
+struct _GskVulkanBlurInstance
+{
+  float rect[4];
+  float tex_rect[4];
+  float blur_radius;
+};
+
+G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanBlurInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_rect),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_blur_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanBlurPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_blur_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_blur_pipeline_class_init (GskVulkanBlurPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blur_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_blur_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_blur_pipeline_init (GskVulkanBlurPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_blur_pipeline_new (GdkVulkanContext        *context,
+                              VkPipelineLayout         layout,
+                              const char              *shader_name,
+                              VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLUR_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline)
+{
+  return sizeof (GskVulkanBlurInstance);
+}
+
+void
+gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
+                                              guchar                *data,
+                                              const graphene_rect_t *rect,
+                                              const graphene_rect_t *tex_rect,
+                                              double                 blur_radius)
+{
+  GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
+
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+  instance->tex_rect[0] = tex_rect->origin.x;
+  instance->tex_rect[1] = tex_rect->origin.y;
+  instance->tex_rect[2] = tex_rect->size.width;
+  instance->tex_rect[3] = tex_rect->size.height;
+  instance->blur_radius = blur_radius;
+}
+
+gsize
+gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
+                               VkCommandBuffer        command_buffer,
+                               gsize                  offset,
+                               gsize                  n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkanblurpipelineprivate.h b/gsk/vulkan/gskvulkanblurpipelineprivate.h
new file mode 100644 (file)
index 0000000..0fc2cb6
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBlurPipelineLayout GskVulkanBlurPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BLUR_PIPELINE (gsk_vulkan_blur_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK, VULKAN_BLUR_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_blur_pipeline_new                   (GdkVulkanContext        *context,
+                                                                        VkPipelineLayout         layout,
+                                                                        const char              *shader_name,
+                                                                        VkRenderPass             render_pass);
+
+gsize                   gsk_vulkan_blur_pipeline_count_vertex_data     (GskVulkanBlurPipeline   *pipeline);
+void                    gsk_vulkan_blur_pipeline_collect_vertex_data   (GskVulkanBlurPipeline   *pipeline,
+                                                                        guchar                  *data,
+                                                                        const graphene_rect_t   *rect,
+                                                                        const graphene_rect_t   *tex_rect,
+                                                                        double                   radius);
+gsize                   gsk_vulkan_blur_pipeline_draw                  (GskVulkanBlurPipeline   *pipeline,
+                                                                        VkCommandBuffer          command_buffer,
+                                                                        gsize                    offset,
+                                                                        gsize                    n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanborderpipeline.c b/gsk/vulkan/gskvulkanborderpipeline.c
new file mode 100644 (file)
index 0000000..a0da439
--- /dev/null
@@ -0,0 +1,164 @@
+#include "config.h"
+
+#include "gskvulkanborderpipelineprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+struct _GskVulkanBorderPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
+
+struct _GskVulkanBorderInstance
+{
+  float rect[12];
+  float widths[4];
+  float colors[16];
+};
+
+G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanBorderInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
+      },
+      {
+          .location = 4,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
+      },
+      {
+          .location = 5,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
+      },
+      {
+          .location = 6,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
+      },
+      {
+          .location = 7,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_border_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_border_pipeline_new (GdkVulkanContext        *context,
+                                VkPipelineLayout         layout,
+                                const char              *shader_name,
+                                VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
+{
+  return sizeof (GskVulkanBorderInstance);
+}
+
+void
+gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
+                                                guchar                  *data,
+                                                const GskRoundedRect    *rect,
+                                                const float              widths[4],
+                                                const GdkRGBA            colors[4])
+{
+  GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
+  guint i;
+
+  gsk_rounded_rect_to_float (rect, instance->rect);
+  for (i = 0; i < 4; i++)
+    {
+      instance->widths[i] = widths[i];
+      instance->colors[4 * i + 0] = colors[i].red;
+      instance->colors[4 * i + 1] = colors[i].green;
+      instance->colors[4 * i + 2] = colors[i].blue;
+      instance->colors[4 * i + 3] = colors[i].alpha;
+    }
+}
+
+gsize
+gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
+                                VkCommandBuffer         command_buffer,
+                                gsize                   offset,
+                                gsize                   n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6 * 8, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkanborderpipelineprivate.h b/gsk/vulkan/gskvulkanborderpipelineprivate.h
new file mode 100644 (file)
index 0000000..d826792
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskroundedrect.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_border_pipeline_new                  (GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_border_pipeline_count_vertex_data    (GskVulkanBorderPipeline        *pipeline);
+void                    gsk_vulkan_border_pipeline_collect_vertex_data  (GskVulkanBorderPipeline        *pipeline,
+                                                                         guchar                         *data,
+                                                                         const GskRoundedRect           *rect,
+                                                                         const float                     widths[4],
+                                                                         const GdkRGBA                   colors[4]);
+gsize                   gsk_vulkan_border_pipeline_draw                 (GskVulkanBorderPipeline        *pipeline,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         gsize                           offset,
+                                                                         gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanboxshadowpipeline.c b/gsk/vulkan/gskvulkanboxshadowpipeline.c
new file mode 100644 (file)
index 0000000..fb27217
--- /dev/null
@@ -0,0 +1,162 @@
+#include "config.h"
+
+#include "gskvulkanboxshadowpipelineprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+struct _GskVulkanBoxShadowPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanBoxShadowInstance GskVulkanBoxShadowInstance;
+
+struct _GskVulkanBoxShadowInstance
+{
+  float outline[12];
+  float color[4];
+  float offset[2];
+  float spread;
+  float blur_radius;
+};
+
+G_DEFINE_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_box_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanBoxShadowInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline),
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 4 * sizeof (float),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 8 * sizeof (float),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, color),
+      },
+      {
+          .location = 4,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, offset),
+      },
+      {
+          .location = 5,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, spread),
+      },
+      {
+          .location = 6,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, blur_radius),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanBoxShadowPipeline *self = GSK_VULKAN_BOX_SHADOW_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_box_shadow_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_class_init (GskVulkanBoxShadowPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_box_shadow_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_box_shadow_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_init (GskVulkanBoxShadowPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext        *context,
+                                    VkPipelineLayout         layout,
+                                    const char              *shader_name,
+                                    VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline)
+{
+  return sizeof (GskVulkanBoxShadowInstance);
+}
+
+void
+gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
+                                                    guchar                     *data,
+                                                    const GskRoundedRect       *outline,
+                                                    const GdkRGBA              *color,
+                                                    float                      dx,
+                                                    float                      dy,
+                                                    float                      spread,
+                                                    float                      blur_radius)
+{
+  GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
+
+  gsk_rounded_rect_to_float (outline, instance->outline);
+  instance->color[0] = color->red;
+  instance->color[1] = color->green;
+  instance->color[2] = color->blue;
+  instance->color[3] = color->alpha;
+  instance->offset[0] = dx;
+  instance->offset[1] = dy;
+  instance->spread = spread;
+  instance->blur_radius = blur_radius;
+}
+
+gsize
+gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
+                                     VkCommandBuffer         command_buffer,
+                                     gsize                   offset,
+                                     gsize                   n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6 * 8, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkanboxshadowpipelineprivate.h b/gsk/vulkan/gskvulkanboxshadowpipelineprivate.h
new file mode 100644 (file)
index 0000000..975338b
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskroundedrect.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBoxShadowPipelineLayout GskVulkanBoxShadowPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE (gsk_vulkan_box_shadow_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK, VULKAN_BOX_SHADOW_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_box_shadow_pipeline_new              (GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline    *pipeline);
+void                    gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline  *pipeline,
+                                                                         guchar                         *data,
+                                                                         const GskRoundedRect           *outline,
+                                                                         const GdkRGBA                  *color,
+                                                                         float                           dx,
+                                                                         float                           dy,
+                                                                         float                           spread,
+                                                                         float                           blur_radius);
+
+gsize                   gsk_vulkan_box_shadow_pipeline_draw             (GskVulkanBoxShadowPipeline     *pipeline,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         gsize                           offset,
+                                                                         gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanbuffer.c b/gsk/vulkan/gskvulkanbuffer.c
new file mode 100644 (file)
index 0000000..291e340
--- /dev/null
@@ -0,0 +1,110 @@
+#include "config.h"
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanmemoryprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanBuffer
+{
+  GdkVulkanContext *vulkan;
+
+  gsize size;
+
+  VkBuffer vk_buffer;
+
+  GskVulkanMemory *memory;
+};
+
+static GskVulkanBuffer *
+gsk_vulkan_buffer_new_internal (GdkVulkanContext  *context,
+                                gsize              size,
+                                VkBufferUsageFlags usage)
+{
+  VkMemoryRequirements requirements;
+  GskVulkanBuffer *self;
+
+  self = g_slice_new0 (GskVulkanBuffer);
+
+  self->vulkan = g_object_ref (context);
+  self->size = size;
+
+  GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context),
+                                &(VkBufferCreateInfo) {
+                                    .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+                                    .size = size,
+                                    .flags = 0,
+                                    .usage = usage,
+                                    .sharingMode = VK_SHARING_MODE_EXCLUSIVE
+                                },
+                                NULL,
+                                &self->vk_buffer);
+
+  vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context),
+                                 self->vk_buffer,
+                                 &requirements);
+
+  self->memory = gsk_vulkan_memory_new (context,
+                                        requirements.memoryTypeBits,
+                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+                                        size);
+
+  GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context),
+                                    self->vk_buffer,
+                                    gsk_vulkan_memory_get_device_memory (self->memory),
+                                    0);
+  return self;
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new (GdkVulkanContext  *context,
+                       gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size,
+                                         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+                                         | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_staging (GdkVulkanContext  *context,
+                               gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_download (GdkVulkanContext  *context,
+                                gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+}
+void
+gsk_vulkan_buffer_free (GskVulkanBuffer *self)
+{
+  vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan),
+                   self->vk_buffer,
+                   NULL);
+
+  gsk_vulkan_memory_free (self->memory);
+
+  g_object_unref (self->vulkan);
+
+  g_slice_free (GskVulkanBuffer, self);
+}
+
+VkBuffer
+gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
+{
+  return self->vk_buffer;
+}
+
+guchar *
+gsk_vulkan_buffer_map (GskVulkanBuffer *self)
+{
+  return gsk_vulkan_memory_map (self->memory);
+}
+
+void
+gsk_vulkan_buffer_unmap (GskVulkanBuffer *self)
+{
+  gsk_vulkan_memory_unmap (self->memory);
+}
diff --git a/gsk/vulkan/gskvulkanbufferprivate.h b/gsk/vulkan/gskvulkanbufferprivate.h
new file mode 100644 (file)
index 0000000..700e400
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__
+#define __GSK_VULKAN_BUFFER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBuffer GskVulkanBuffer;
+
+GskVulkanBuffer *       gsk_vulkan_buffer_new                           (GdkVulkanContext       *context,
+                                                                         gsize                   size);
+GskVulkanBuffer *       gsk_vulkan_buffer_new_staging                   (GdkVulkanContext       *context,
+                                                                         gsize                   size);
+GskVulkanBuffer *       gsk_vulkan_buffer_new_download                  (GdkVulkanContext       *context,
+                                                                         gsize                   size);
+void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
+
+VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
+
+guchar *                gsk_vulkan_buffer_map                           (GskVulkanBuffer        *self);
+void                    gsk_vulkan_buffer_unmap                         (GskVulkanBuffer        *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BUFFER_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanclip.c b/gsk/vulkan/gskvulkanclip.c
new file mode 100644 (file)
index 0000000..d927d88
--- /dev/null
@@ -0,0 +1,187 @@
+#include "config.h"
+
+#include "gskvulkanclipprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+void
+gsk_vulkan_clip_init_empty (GskVulkanClip         *clip,
+                            const graphene_rect_t *rect)
+{
+  clip->type = GSK_VULKAN_CLIP_NONE;
+  gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
+}
+
+static void
+gsk_vulkan_clip_init_copy (GskVulkanClip *self,
+                           const GskVulkanClip *src)
+{
+  self->type = src->type;
+  gsk_rounded_rect_init_copy (&self->rect, &src->rect);
+}
+
+gboolean
+gsk_vulkan_clip_intersect_rect (GskVulkanClip         *dest,
+                                const GskVulkanClip   *src,
+                                const graphene_rect_t *rect)
+{
+  if (graphene_rect_contains_rect (rect, &src->rect.bounds))
+    {
+      gsk_vulkan_clip_init_copy (dest, src);
+      return TRUE;
+    }
+  if (!graphene_rect_intersection (rect, &src->rect.bounds, NULL))
+    {
+      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      return TRUE;
+    }
+
+  switch (src->type)
+    {
+    case GSK_VULKAN_CLIP_ALL_CLIPPED:
+      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      break;
+
+    case GSK_VULKAN_CLIP_NONE:
+      gsk_vulkan_clip_init_copy (dest, src);
+      if (graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
+        dest->type = GSK_VULKAN_CLIP_RECT;
+      else
+        dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      break;
+
+    case GSK_VULKAN_CLIP_RECT:
+      gsk_vulkan_clip_init_copy (dest, src);
+      if (!graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
+        dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      break;
+
+    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+    case GSK_VULKAN_CLIP_ROUNDED:
+      if (gsk_rounded_rect_contains_rect (&src->rect, rect))
+        {
+          dest->type = GSK_VULKAN_CLIP_RECT;
+          gsk_rounded_rect_init_from_rect (&dest->rect, rect, 0);
+        }
+      else
+        {
+          /* some points of rect are inside src's rounded rect,
+           * some are outside. */
+          /* XXX: If the 2 rects don't intersect on rounded corners,
+           * we could actually compute a new clip here.
+           */
+          return FALSE;
+        }
+
+    default:
+      g_assert_not_reached ();
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip        *dest,
+                                        const GskVulkanClip  *src,
+                                        const GskRoundedRect *rounded)
+{
+  if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
+    {
+      gsk_vulkan_clip_init_copy (dest, src);
+      return TRUE;
+    }
+  if (!graphene_rect_intersection (&rounded->bounds, &src->rect.bounds, NULL))
+    {
+      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      return TRUE;
+    }
+
+  switch (src->type)
+    {
+    case GSK_VULKAN_CLIP_ALL_CLIPPED:
+      dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+      break;
+
+    case GSK_VULKAN_CLIP_NONE:
+      dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
+      gsk_rounded_rect_init_copy (&dest->rect, rounded);
+      break;
+
+    case GSK_VULKAN_CLIP_RECT:
+      if (graphene_rect_contains_rect (&src->rect.bounds, &rounded->bounds))
+        {
+          dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
+          gsk_rounded_rect_init_copy (&dest->rect, rounded);
+          return TRUE;
+        }
+      /* some points of rect are inside src's rounded rect,
+       * some are outside. */
+      /* XXX: If the 2 rects don't intersect on rounded corners,
+       * we could actually compute a new clip here.
+       */
+      return FALSE;
+
+    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+    case GSK_VULKAN_CLIP_ROUNDED:
+      /* XXX: improve */
+      return FALSE;
+
+    default:
+      g_assert_not_reached ();
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+gsk_vulkan_clip_transform (GskVulkanClip           *dest,
+                           const GskVulkanClip     *src,
+                           const graphene_matrix_t *transform,
+                           const graphene_rect_t   *viewport)
+{
+  switch (src->type)
+    {
+    default:
+      g_assert_not_reached();
+      return FALSE;
+
+    case GSK_VULKAN_CLIP_ALL_CLIPPED:
+      gsk_vulkan_clip_init_copy (dest, src);
+      return TRUE;
+
+    case GSK_VULKAN_CLIP_NONE:
+      gsk_vulkan_clip_init_empty (dest, viewport);
+      return TRUE;
+
+    case GSK_VULKAN_CLIP_RECT:
+    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+    case GSK_VULKAN_CLIP_ROUNDED:
+      /* FIXME: Handle 2D operations, in particular transform and scale */
+      return FALSE;
+    }
+}
+
+gboolean
+gsk_vulkan_clip_contains_rect (const GskVulkanClip   *self,
+                               const graphene_rect_t *rect)
+{
+  switch (self->type)
+    {
+    default:
+      g_assert_not_reached();
+    case GSK_VULKAN_CLIP_ALL_CLIPPED:
+      return FALSE;
+
+    case GSK_VULKAN_CLIP_NONE:
+      return TRUE;
+
+    case GSK_VULKAN_CLIP_RECT:
+      return graphene_rect_contains_rect (&self->rect.bounds, rect);
+
+    case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+    case GSK_VULKAN_CLIP_ROUNDED:
+      return gsk_rounded_rect_contains_rect (&self->rect, rect);
+    }
+}
diff --git a/gsk/vulkan/gskvulkanclipprivate.h b/gsk/vulkan/gskvulkanclipprivate.h
new file mode 100644 (file)
index 0000000..10b89ed
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __GSK_VULKAN_CLIP_PRIVATE_H__
+#define __GSK_VULKAN_CLIP_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <graphene.h>
+#include <gsk/gskroundedrect.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  /* The whole area is clipped, no drawing is necessary.
+   * This can't be handled by return values because for return
+   * values we return if clips could even be computed.
+   */
+  GSK_VULKAN_CLIP_ALL_CLIPPED,
+  /* No clipping is necessary, but the clip rect is set
+   * to the actual bounds of the underlying framebuffer
+   */
+  GSK_VULKAN_CLIP_NONE,
+  /* The clip is a rectangular area */
+  GSK_VULKAN_CLIP_RECT,
+  /* The clip is a rounded rectangle, and for every corner
+   * corner.width == corner.height is true
+   */
+  GSK_VULKAN_CLIP_ROUNDED_CIRCULAR,
+  /* The clip is a rounded rectangle */
+  GSK_VULKAN_CLIP_ROUNDED
+} GskVulkanClipComplexity;
+
+typedef struct _GskVulkanClip GskVulkanClip;
+
+struct _GskVulkanClip
+{
+  GskVulkanClipComplexity type;
+  GskRoundedRect          rect;
+};
+
+void                    gsk_vulkan_clip_init_empty                      (GskVulkanClip          *clip,
+                                                                         const graphene_rect_t  *rect);
+
+gboolean                gsk_vulkan_clip_intersect_rect                  (GskVulkanClip          *dest,
+                                                                         const GskVulkanClip    *src,
+                                                                         const graphene_rect_t  *rect) G_GNUC_WARN_UNUSED_RESULT;
+gboolean                gsk_vulkan_clip_intersect_rounded_rect          (GskVulkanClip          *dest,
+                                                                         const GskVulkanClip    *src,
+                                                                         const GskRoundedRect   *rounded) G_GNUC_WARN_UNUSED_RESULT;
+gboolean                gsk_vulkan_clip_transform                       (GskVulkanClip          *dest,
+                                                                         const GskVulkanClip    *src,
+                                                                         const graphene_matrix_t*transform,
+                                                                         const graphene_rect_t  *viewport) G_GNUC_WARN_UNUSED_RESULT;
+
+gboolean                gsk_vulkan_clip_contains_rect                   (const GskVulkanClip    *self,
+                                                                         const graphene_rect_t  *rect) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_CLIP_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkancolorpipeline.c b/gsk/vulkan/gskvulkancolorpipeline.c
new file mode 100644 (file)
index 0000000..cd6867a
--- /dev/null
@@ -0,0 +1,122 @@
+#include "config.h"
+
+#include "gskvulkancolorpipelineprivate.h"
+
+struct _GskVulkanColorPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanColorInstance GskVulkanColorInstance;
+
+struct _GskVulkanColorInstance
+{
+  float rect[4];
+  float color[4];
+};
+
+G_DEFINE_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_color_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanColorInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanColorInstance, color),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_color_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanColorPipeline *self = GSK_VULKAN_COLOR_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_color_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_color_pipeline_class_init (GskVulkanColorPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_color_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_color_pipeline_init (GskVulkanColorPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_color_pipeline_new (GdkVulkanContext         *context,
+                               VkPipelineLayout         layout,
+                               const char              *shader_name,
+                               VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline)
+{
+  return sizeof (GskVulkanColorInstance);
+}
+
+void
+gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
+                                               guchar                 *data,
+                                               const graphene_rect_t  *rect,
+                                               const GdkRGBA          *color)
+{
+  GskVulkanColorInstance *instance = (GskVulkanColorInstance *) data;
+
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+  instance->color[0] = color->red;
+  instance->color[1] = color->green;
+  instance->color[2] = color->blue;
+  instance->color[3] = color->alpha;
+}
+
+gsize
+gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
+                                VkCommandBuffer         command_buffer,
+                                gsize                   offset,
+                                gsize                   n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkancolorpipelineprivate.h b/gsk/vulkan/gskvulkancolorpipelineprivate.h
new file mode 100644 (file)
index 0000000..b9ae514
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanColorPipelineLayout GskVulkanColorPipelineLayout;
+
+#define GSK_TYPE_VULKAN_COLOR_PIPELINE (gsk_vulkan_color_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK, VULKAN_COLOR_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_color_pipeline_new                   (GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_color_pipeline_count_vertex_data     (GskVulkanColorPipeline         *pipeline);
+void                    gsk_vulkan_color_pipeline_collect_vertex_data   (GskVulkanColorPipeline         *pipeline,
+                                                                         guchar                         *data,
+                                                                         const graphene_rect_t          *rect,
+                                                                         const GdkRGBA                  *color);
+gsize                   gsk_vulkan_color_pipeline_draw                  (GskVulkanColorPipeline         *pipeline,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         gsize                           offset,
+                                                                         gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkancolortextpipeline.c b/gsk/vulkan/gskvulkancolortextpipeline.c
new file mode 100644 (file)
index 0000000..9770b27
--- /dev/null
@@ -0,0 +1,157 @@
+#include "config.h"
+
+#include "gskvulkancolortextpipelineprivate.h"
+
+struct _GskVulkanColorTextPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
+
+struct _GskVulkanColorTextInstance
+{
+  float rect[4];
+  float tex_rect[4];
+};
+
+G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanColorTextInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
+      },
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_color_text_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanColorTextPipeline *self = GSK_VULKAN_COLOR_TEXT_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_color_text_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_color_text_pipeline_class_init (GskVulkanColorTextPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_text_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_color_text_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_color_text_pipeline_init (GskVulkanColorTextPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_color_text_pipeline_new (GdkVulkanContext        *context,
+                                    VkPipelineLayout         layout,
+                                    const char              *shader_name,
+                                    VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, context, layout, shader_name, render_pass,
+                                       VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+gsize
+gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
+                                                  int                         num_instances)
+{
+  return sizeof (GskVulkanColorTextInstance) * num_instances;
+}
+
+void
+gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
+                                                    guchar                     *data,
+                                                    GskVulkanRenderer          *renderer,
+                                                    const graphene_rect_t      *rect,
+                                                    PangoFont                  *font,
+                                                    guint                       total_glyphs,
+                                                    const PangoGlyphInfo       *glyphs,
+                                                    float                       x,
+                                                    float                       y,
+                                                    guint                       start_glyph,
+                                                    guint                       num_glyphs,
+                                                    float                       scale)
+{
+  GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) data;
+  int i;
+  int count = 0;
+  int x_position = 0;
+
+  for (i = 0; i < start_glyph; i++)
+    x_position += glyphs[i].geometry.width;
+
+  for (; i < total_glyphs && count < num_glyphs; i++)
+    {
+      const PangoGlyphInfo *gi = &glyphs[i];
+
+      if (gi->glyph != PANGO_GLYPH_EMPTY)
+        {
+          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+          GskVulkanColorTextInstance *instance = &instances[count];
+          GskVulkanCachedGlyph *glyph;
+
+          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+
+          instance->tex_rect[0] = glyph->tx;
+          instance->tex_rect[1] = glyph->ty;
+          instance->tex_rect[2] = glyph->tw;
+          instance->tex_rect[3] = glyph->th;
+
+          instance->rect[0] = x + cx + glyph->draw_x;
+          instance->rect[1] = y + cy + glyph->draw_y;
+          instance->rect[2] = glyph->draw_width;
+          instance->rect[3] = glyph->draw_height;
+
+          count++;
+       }
+     x_position += gi->geometry.width;
+   }
+}
+
+gsize
+gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
+                                     VkCommandBuffer             command_buffer,
+                                     gsize                       offset,
+                                     gsize                       n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkancolortextpipelineprivate.h b/gsk/vulkan/gskvulkancolortextpipelineprivate.h
new file mode 100644 (file)
index 0000000..2e46b1c
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrendererprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanColorTextPipelineLayout GskVulkanColorTextPipelineLayout;
+
+#define GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE (gsk_vulkan_color_text_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK, VULKAN_COLOR_TEXT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_color_text_pipeline_new                   (GdkVulkanContext               *context,
+                                                                              VkPipelineLayout                layout,
+                                                                              const char                     *shader_name,
+                                                                              VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_color_text_pipeline_count_vertex_data     (GskVulkanColorTextPipeline     *pipeline,
+                                                                              int                             num_instances);
+void                    gsk_vulkan_color_text_pipeline_collect_vertex_data   (GskVulkanColorTextPipeline     *pipeline,
+                                                                              guchar                         *data,
+                                                                              GskVulkanRenderer              *renderer,
+                                                                              const graphene_rect_t          *rect,
+                                                                              PangoFont                      *font,
+                                                                              guint                           total_glyphs,
+                                                                              const PangoGlyphInfo           *glyphs,
+                                                                              float                           x,
+                                                                              float                           y,
+                                                                              guint                           start_glyph,
+                                                                              guint                           num_glyphs,
+                                                                              float                           scale);
+gsize                   gsk_vulkan_color_text_pipeline_draw                  (GskVulkanColorTextPipeline     *pipeline,
+                                                                              VkCommandBuffer                 command_buffer,
+                                                                              gsize                           offset,
+                                                                              gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkancommandpool.c b/gsk/vulkan/gskvulkancommandpool.c
new file mode 100644 (file)
index 0000000..bcba6a9
--- /dev/null
@@ -0,0 +1,111 @@
+#include "config.h"
+
+#include "gskvulkancommandpoolprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanCommandPool
+{
+  GdkVulkanContext *vulkan;
+
+  VkCommandPool vk_command_pool;
+};
+
+GskVulkanCommandPool *
+gsk_vulkan_command_pool_new (GdkVulkanContext *context)
+{
+  GskVulkanCommandPool *self;
+
+  self = g_slice_new0 (GskVulkanCommandPool);
+
+  self->vulkan = g_object_ref (context);
+
+  GSK_VK_CHECK (vkCreateCommandPool, gdk_vulkan_context_get_device (context),
+                                     &(const VkCommandPoolCreateInfo) {
+                                         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+                                         .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan),
+                                         .flags = 0
+                                     },
+                                     NULL,
+                                     &self->vk_command_pool);
+
+  return self;
+}
+
+void
+gsk_vulkan_command_pool_free (GskVulkanCommandPool *self)
+{
+  vkDestroyCommandPool (gdk_vulkan_context_get_device (self->vulkan),
+                        self->vk_command_pool,
+                        NULL);
+
+  g_slice_free (GskVulkanCommandPool, self);
+}
+
+void
+gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self)
+{
+  GSK_VK_CHECK (vkResetCommandPool, gdk_vulkan_context_get_device (self->vulkan),
+                                    self->vk_command_pool,
+                                    0);
+}
+
+VkCommandBuffer
+gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self)
+{
+  VkCommandBuffer command_buffer;
+
+  GSK_VK_CHECK (vkAllocateCommandBuffers, gdk_vulkan_context_get_device (self->vulkan),
+                                          &(VkCommandBufferAllocateInfo) {
+                                              .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+                                              .commandPool = self->vk_command_pool,
+                                              .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+                                              .commandBufferCount = 1,
+                                          },
+                                          &command_buffer);
+
+  GSK_VK_CHECK (vkBeginCommandBuffer, command_buffer,
+                                      &(VkCommandBufferBeginInfo) {
+                                          .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+                                          .flags = 0
+                                      });
+
+  return command_buffer;
+}
+
+void
+gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
+                                       VkCommandBuffer       command_buffer,
+                                       gsize                 wait_semaphore_count,
+                                       VkSemaphore          *wait_semaphores,
+                                       gsize                 signal_semaphore_count,
+                                       VkSemaphore          *signal_semaphores,
+                                       VkFence               fence)
+{
+  VkPipelineStageFlags *wait_semaphore_flags = NULL;
+
+  GSK_VK_CHECK (vkEndCommandBuffer, command_buffer);
+
+  if (wait_semaphore_count > 0)
+    {
+      wait_semaphore_flags = alloca (sizeof (VkPipelineStageFlags) * wait_semaphore_count);
+      for (int i = 0; i < wait_semaphore_count; i++)
+        wait_semaphore_flags[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+    }
+
+  GSK_VK_CHECK (vkQueueSubmit, gdk_vulkan_context_get_queue (self->vulkan),
+                               1,
+                               &(VkSubmitInfo) {
+                                  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                                  .waitSemaphoreCount = wait_semaphore_count,
+                                  .pWaitSemaphores = wait_semaphores,
+                                  .pWaitDstStageMask = wait_semaphore_flags,
+                                  .commandBufferCount = 1,
+                                  .pCommandBuffers = (VkCommandBuffer[1]) {
+                                      command_buffer
+                                  },
+                                  .signalSemaphoreCount = signal_semaphore_count,
+                                  .pSignalSemaphores = signal_semaphores,
+                               },
+                               fence);
+}
+
diff --git a/gsk/vulkan/gskvulkancommandpoolprivate.h b/gsk/vulkan/gskvulkancommandpoolprivate.h
new file mode 100644 (file)
index 0000000..bb362f3
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
+#define __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanCommandPool GskVulkanCommandPool;
+
+GskVulkanCommandPool *  gsk_vulkan_command_pool_new                     (GdkVulkanContext       *context);
+void                    gsk_vulkan_command_pool_free                    (GskVulkanCommandPool   *self);
+
+void                    gsk_vulkan_command_pool_reset                   (GskVulkanCommandPool   *self);
+
+VkCommandBuffer         gsk_vulkan_command_pool_get_buffer              (GskVulkanCommandPool   *self);
+void                    gsk_vulkan_command_pool_submit_buffer           (GskVulkanCommandPool   *self,
+                                                                         VkCommandBuffer         buffer,
+                                                                         gsize                   wait_semaphore_count,
+                                                                         VkSemaphore            *wait_semaphores,
+                                                                         gsize                   signal_semaphores_count,
+                                                                         VkSemaphore            *signal_semaphores,
+                                                                         VkFence                 fence);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkancrossfadepipeline.c b/gsk/vulkan/gskvulkancrossfadepipeline.c
new file mode 100644 (file)
index 0000000..679c583
--- /dev/null
@@ -0,0 +1,146 @@
+#include "config.h"
+
+#include "gskvulkancrossfadepipelineprivate.h"
+
+struct _GskVulkanCrossFadePipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
+
+struct _GskVulkanCrossFadeInstance
+{
+  float rect[4];
+  float start_tex_rect[4];
+  float end_tex_rect[4];
+  float progress;
+};
+
+G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanCrossFadeInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext        *context,
+                                    VkPipelineLayout         layout,
+                                    const char              *shader_name,
+                                    VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
+{
+  return sizeof (GskVulkanCrossFadeInstance);
+}
+
+void
+gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
+                                                    guchar                *data,
+                                                    const graphene_rect_t *bounds,
+                                                    const graphene_rect_t *start_tex_rect,
+                                                    const graphene_rect_t *end_tex_rect,
+                                                    double                 progress)
+{
+  GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data;
+
+  instance->rect[0] = bounds->origin.x;
+  instance->rect[1] = bounds->origin.y;
+  instance->rect[2] = bounds->size.width;
+  instance->rect[3] = bounds->size.height;
+
+  instance->start_tex_rect[0] = start_tex_rect->origin.x;
+  instance->start_tex_rect[1] = start_tex_rect->origin.y;
+  instance->start_tex_rect[2] = start_tex_rect->size.width;
+  instance->start_tex_rect[3] = start_tex_rect->size.height;
+
+  instance->end_tex_rect[0] = end_tex_rect->origin.x;
+  instance->end_tex_rect[1] = end_tex_rect->origin.y;
+  instance->end_tex_rect[2] = end_tex_rect->size.width;
+  instance->end_tex_rect[3] = end_tex_rect->size.height;
+
+  instance->progress = progress;
+}
+
+gsize
+gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
+                                     VkCommandBuffer        command_buffer,
+                                     gsize                  offset,
+                                     gsize                  n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkancrossfadepipelineprivate.h b/gsk/vulkan/gskvulkancrossfadepipelineprivate.h
new file mode 100644 (file)
index 0000000..da5e820
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout;
+
+#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new                 (GdkVulkanContext           *context,
+                                                                        VkPipelineLayout            layout,
+                                                                        const char                 *shader_name,
+                                                                        VkRenderPass                render_pass);
+
+gsize               gsk_vulkan_cross_fade_pipeline_count_vertex_data   (GskVulkanCrossFadePipeline *pipeline);
+void                gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
+                                                                        guchar                     *data,
+                                                                        const graphene_rect_t      *bounds,
+                                                                        const graphene_rect_t      *start_bounds,
+                                                                        const graphene_rect_t      *end_bounds,
+                                                                        double                      progress);
+gsize               gsk_vulkan_cross_fade_pipeline_draw                (GskVulkanCrossFadePipeline *pipeline,
+                                                                        VkCommandBuffer             command_buffer,
+                                                                        gsize                       offset,
+                                                                        gsize                       n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkaneffectpipeline.c b/gsk/vulkan/gskvulkaneffectpipeline.c
new file mode 100644 (file)
index 0000000..aa9973c
--- /dev/null
@@ -0,0 +1,158 @@
+#include "config.h"
+
+#include "gskvulkaneffectpipelineprivate.h"
+
+struct _GskVulkanEffectPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance;
+
+struct _GskVulkanEffectInstance
+{
+  float rect[4];
+  float tex_rect[4];
+  float color_matrix[16];
+  float color_offset[4];
+};
+
+G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanEffectInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 4,
+      },
+      {
+          .location = 4,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 8,
+      },
+      {
+          .location = 5,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 12,
+      },
+      {
+          .location = 6,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_effect_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_effect_pipeline_new (GdkVulkanContext        *context,
+                                VkPipelineLayout         layout,
+                                const char              *shader_name,
+                                VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline)
+{
+  return sizeof (GskVulkanEffectInstance);
+}
+
+void
+gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
+                                                guchar                  *data,
+                                                const graphene_rect_t   *rect,
+                                                const graphene_rect_t   *tex_rect,
+                                                const graphene_matrix_t *color_matrix,
+                                                const graphene_vec4_t   *color_offset)
+{
+  GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
+
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+  instance->tex_rect[0] = tex_rect->origin.x;
+  instance->tex_rect[1] = tex_rect->origin.y;
+  instance->tex_rect[2] = tex_rect->size.width;
+  instance->tex_rect[3] = tex_rect->size.height;
+  graphene_matrix_to_float (color_matrix, instance->color_matrix);
+  graphene_vec4_to_float (color_offset, instance->color_offset);
+}
+
+gsize
+gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
+                                VkCommandBuffer           command_buffer,
+                                gsize                     offset,
+                                gsize                     n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkaneffectpipelineprivate.h b/gsk/vulkan/gskvulkaneffectpipelineprivate.h
new file mode 100644 (file)
index 0000000..45ac6af
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout;
+
+#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_effect_pipeline_new                  (GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_effect_pipeline_count_vertex_data    (GskVulkanEffectPipeline        *pipeline);
+void                    gsk_vulkan_effect_pipeline_collect_vertex_data  (GskVulkanEffectPipeline        *pipeline,
+                                                                         guchar                         *data,
+                                                                         const graphene_rect_t          *rect,
+                                                                         const graphene_rect_t          *tex_rect,
+                                                                         const graphene_matrix_t        *color_matrix,
+                                                                         const graphene_vec4_t          *color_offset);
+gsize                   gsk_vulkan_effect_pipeline_draw                 (GskVulkanEffectPipeline        *pipeline,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         gsize                           offset,
+                                                                         gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanglyphcache.c b/gsk/vulkan/gskvulkanglyphcache.c
new file mode 100644 (file)
index 0000000..8d12f5c
--- /dev/null
@@ -0,0 +1,483 @@
+#include "config.h"
+
+#include "gskvulkanglyphcacheprivate.h"
+
+#include "gskvulkanimageprivate.h"
+#include "gskdebugprivate.h"
+#include "gskprivate.h"
+
+#include <graphene.h>
+
+/* Parameters for our cache eviction strategy.
+ *
+ * Each cached glyph has an age that gets reset every time a cached glyph gets used.
+ * Glyphs that have not been used for the MAX_AGE frames are considered old. We keep
+ * count of the pixels of each atlas that are taken up by old glyphs. We check the
+ * fraction of old pixels every CHECK_INTERVAL frames, and if it is above MAX_OLD, then
+ * we drop the atlas an all the glyphs contained in it from the cache.
+ */
+
+#define MAX_AGE 60
+#define CHECK_INTERVAL 10
+#define MAX_OLD 0.333
+
+
+typedef struct {
+  GskVulkanImage *image;
+  int width, height;
+  int x, y, y0;
+  int num_glyphs;
+  GList *dirty_glyphs;
+  guint old_pixels;
+} Atlas;
+
+struct _GskVulkanGlyphCache {
+  GObject parent_instance;
+
+  GdkVulkanContext *vulkan;
+
+  GHashTable *hash_table;
+  GPtrArray *atlases;
+
+  guint64 timestamp;
+};
+
+struct _GskVulkanGlyphCacheClass {
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GskVulkanGlyphCache, gsk_vulkan_glyph_cache, G_TYPE_OBJECT)
+
+static guint    glyph_cache_hash       (gconstpointer v);
+static gboolean glyph_cache_equal      (gconstpointer v1,
+                                        gconstpointer v2);
+static void     glyph_cache_key_free   (gpointer      v);
+static void     glyph_cache_value_free (gpointer      v);
+static void     dirty_glyph_free       (gpointer      v);
+
+static Atlas *
+create_atlas (GskVulkanGlyphCache *cache)
+{
+  Atlas *atlas;
+
+  atlas = g_new0 (Atlas, 1);
+  atlas->width = 512;
+  atlas->height = 512;
+  atlas->y0 = 1;
+  atlas->y = 1;
+  atlas->x = 1;
+  atlas->image = NULL;
+  atlas->num_glyphs = 0;
+  atlas->dirty_glyphs = NULL;
+
+  return atlas;
+}
+
+static void
+free_atlas (gpointer v)
+{
+  Atlas *atlas = v;
+
+  g_clear_object (&atlas->image);
+  g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
+  g_free (atlas);
+}
+
+static void
+gsk_vulkan_glyph_cache_init (GskVulkanGlyphCache *cache)
+{
+  cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
+                                             glyph_cache_key_free, glyph_cache_value_free);
+  cache->atlases = g_ptr_array_new_with_free_func (free_atlas);
+}
+
+static void
+gsk_vulkan_glyph_cache_finalize (GObject *object)
+{
+  GskVulkanGlyphCache *cache = GSK_VULKAN_GLYPH_CACHE (object);
+
+  g_ptr_array_unref (cache->atlases);
+  g_hash_table_unref (cache->hash_table);
+
+  G_OBJECT_CLASS (gsk_vulkan_glyph_cache_parent_class)->finalize (object);
+}
+
+static void
+gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gsk_vulkan_glyph_cache_finalize;
+}
+
+typedef struct {
+  PangoFont *font;
+  PangoGlyph glyph;
+  guint scale; /* times 1024 */
+} GlyphCacheKey;
+
+static gboolean
+glyph_cache_equal (gconstpointer v1, gconstpointer v2)
+{
+  const GlyphCacheKey *key1 = v1;
+  const GlyphCacheKey *key2 = v2;
+
+  return key1->font == key2->font &&
+         key1->glyph == key2->glyph &&
+         key1->scale == key2->scale;
+}
+
+static guint
+glyph_cache_hash (gconstpointer v)
+{
+  const GlyphCacheKey *key = v;
+
+  return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
+}
+
+static void
+glyph_cache_key_free (gpointer v)
+{
+  GlyphCacheKey *f = v;
+
+  g_object_unref (f->font);
+  g_free (f);
+}
+
+static void
+glyph_cache_value_free (gpointer v)
+{
+  g_free (v);
+}
+
+typedef struct {
+  GlyphCacheKey *key;
+  GskVulkanCachedGlyph *value;
+  cairo_surface_t *surface;
+} DirtyGlyph;
+
+static void
+dirty_glyph_free (gpointer v)
+{
+  DirtyGlyph *glyph = v;
+
+  if (glyph->surface)
+    cairo_surface_destroy (glyph->surface);
+  g_free (glyph);
+}
+
+static void
+add_to_cache (GskVulkanGlyphCache  *cache,
+              GlyphCacheKey        *key,
+              GskVulkanCachedGlyph *value)
+{
+  Atlas *atlas;
+  int i;
+  DirtyGlyph *dirty;
+  int width = value->draw_width * key->scale / 1024;
+  int height = value->draw_height * key->scale / 1024;
+
+  for (i = 0; i < cache->atlases->len; i++)
+    {
+      int x, y, y0;
+
+      atlas = g_ptr_array_index (cache->atlases, i);
+      x = atlas->x;
+      y = atlas->y;
+      y0 = atlas->y0;
+
+      if (atlas->x + width + 1 >= atlas->width)
+        {
+          /* start a new row */
+          y0 = y + 1;
+          x = 1;
+        }
+
+      if (y0 + height + 1 >= atlas->height)
+        continue;
+
+      atlas->y0 = y0;
+      atlas->x = x;
+      atlas->y = y;
+      break;
+    }
+
+  if (i == cache->atlases->len)
+    {
+      atlas = create_atlas (cache);
+      g_ptr_array_add (cache->atlases, atlas);
+    }
+
+  value->tx = (float)atlas->x / atlas->width;
+  value->ty = (float)atlas->y0 / atlas->height;
+  value->tw = (float)width / atlas->width;
+  value->th = (float)height / atlas->height;
+
+  value->texture_index = i;
+
+  dirty = g_new (DirtyGlyph, 1);
+  dirty->key = key;
+  dirty->value = value;
+  atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
+
+  atlas->x = atlas->x + width + 1;
+  atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
+
+  atlas->num_glyphs++;
+
+#ifdef G_ENABLE_DEBUG
+  if (GSK_DEBUG_CHECK(GLYPH_CACHE))
+    {
+      g_print ("Glyph cache:\n");
+      for (i = 0; i < cache->atlases->len; i++)
+        {
+          atlas = g_ptr_array_index (cache->atlases, i);
+          g_print ("\tAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
+                   i, atlas->width, atlas->height,
+                   atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
+                   100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
+                   atlas->x, atlas->y0, atlas->y);
+        }
+    }
+#endif
+}
+
+static void
+render_glyph (Atlas          *atlas,
+              DirtyGlyph     *glyph,
+              GskImageRegion *region)
+{
+  GlyphCacheKey *key = glyph->key;
+  GskVulkanCachedGlyph *value = glyph->value;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  PangoGlyphString glyphs;
+  PangoGlyphInfo gi;
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                        value->draw_width * key->scale / 1024,
+                                        value->draw_height * key->scale / 1024);
+  cairo_surface_set_device_scale (surface, key->scale / 1024.0, key->scale / 1024.0);
+
+  cr = cairo_create (surface);
+  cairo_set_source_rgba (cr, 1, 1, 1, 1);
+
+  gi.glyph = key->glyph;
+  gi.geometry.width = value->draw_width * 1024;
+  if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    gi.geometry.x_offset = 0;
+  else
+    gi.geometry.x_offset = - value->draw_x * 1024;
+  gi.geometry.y_offset = - value->draw_y * 1024;
+
+  glyphs.num_glyphs = 1;
+  glyphs.glyphs = &gi;
+
+  pango_cairo_show_glyph_string (cr, key->font, &glyphs);
+
+  cairo_destroy (cr);
+
+  glyph->surface = surface;
+
+  region->data = cairo_image_surface_get_data (surface);
+  region->width = cairo_image_surface_get_width (surface);
+  region->height = cairo_image_surface_get_height (surface);
+  region->stride = cairo_image_surface_get_stride (surface);
+  region->x = (gsize)(value->tx * atlas->width);
+  region->y = (gsize)(value->ty * atlas->height);
+}
+
+static void
+upload_dirty_glyphs (Atlas             *atlas,
+                     GskVulkanUploader *uploader)
+{
+  GList *l;
+  guint num_regions;
+  GskImageRegion *regions;
+  int i;
+
+  num_regions = g_list_length (atlas->dirty_glyphs);
+  regions = alloca (sizeof (GskImageRegion) * num_regions);
+
+  for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
+    render_glyph (atlas, (DirtyGlyph *)l->data, &regions[i]);
+
+  GSK_NOTE (GLYPH_CACHE,
+            g_print ("uploading %d glyphs to cache\n", num_regions));
+
+  gsk_vulkan_image_upload_regions (atlas->image, uploader, num_regions, regions);
+
+  g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
+  atlas->dirty_glyphs = NULL;
+}
+
+GskVulkanGlyphCache *
+gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan)
+{
+  GskVulkanGlyphCache *cache;
+
+  cache = GSK_VULKAN_GLYPH_CACHE (g_object_new (GSK_TYPE_VULKAN_GLYPH_CACHE, NULL));
+  cache->vulkan = vulkan;
+  g_ptr_array_add (cache->atlases, create_atlas (cache));
+
+  return cache;
+}
+
+GskVulkanCachedGlyph *
+gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
+                               gboolean             create,
+                               PangoFont           *font,
+                               PangoGlyph           glyph,
+                               float                scale)
+{
+  GlyphCacheKey lookup_key;
+  GskVulkanCachedGlyph *value;
+
+  lookup_key.font = font;
+  lookup_key.glyph = glyph;
+  lookup_key.scale = (guint)(scale * 1024);
+
+  value = g_hash_table_lookup (cache->hash_table, &lookup_key);
+
+  if (value)
+    {
+      if (cache->timestamp - value->timestamp >= MAX_AGE)
+        {
+          Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
+
+          atlas->old_pixels -= value->draw_width * value->draw_height;
+          value->timestamp = cache->timestamp;
+        }
+    }
+
+  if (create && value == NULL)
+    {
+      GlyphCacheKey *key;
+      PangoRectangle ink_rect;
+
+      key = g_new (GlyphCacheKey, 1);
+      value = g_new0 (GskVulkanCachedGlyph, 1);
+
+      pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
+      pango_extents_to_pixels (&ink_rect, NULL);
+
+      value->draw_x = ink_rect.x;
+      value->draw_y = ink_rect.y;
+      value->draw_width = ink_rect.width;
+      value->draw_height = ink_rect.height;
+      value->timestamp = cache->timestamp;
+
+      key->font = g_object_ref (font);
+      key->glyph = glyph;
+      key->scale = (guint)(scale * 1024);
+
+      if (ink_rect.width > 0 && ink_rect.height > 0)
+        add_to_cache (cache, key, value);
+
+      g_hash_table_insert (cache->hash_table, key, value);
+    }
+
+  return value;
+}
+
+GskVulkanImage *
+gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
+                                        GskVulkanUploader   *uploader,
+                                        guint                index)
+{
+  Atlas *atlas;
+
+  g_return_val_if_fail (index < cache->atlases->len, NULL);
+
+  atlas = g_ptr_array_index (cache->atlases, index);
+
+  if (atlas->image == NULL)
+    atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height);
+
+  if (atlas->dirty_glyphs)
+    upload_dirty_glyphs (atlas, uploader);
+
+  return atlas->image;
+}
+
+void
+gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache)
+{
+  int i, j;
+  guint *drops;
+  guint *shifts;
+  guint len;
+  GHashTableIter iter;
+  GlyphCacheKey *key;
+  GskVulkanCachedGlyph *value;
+  guint dropped = 0;
+
+  cache->timestamp++;
+
+  if (cache->timestamp % CHECK_INTERVAL != 0)
+    return;
+
+  len = cache->atlases->len;
+
+  /* look for glyphs that have grown old since last time */
+  g_hash_table_iter_init (&iter, cache->hash_table);
+  while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+    {
+      guint age;
+
+      age = cache->timestamp - value->timestamp;
+      if (MAX_AGE <= age && age < MAX_AGE + CHECK_INTERVAL)
+        {
+          Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
+          atlas->old_pixels += value->draw_width * value->draw_height;
+        }
+    }
+
+  drops = g_alloca (sizeof (guint) * len);
+  shifts = g_alloca (sizeof (guint) * len);
+
+  for (i = 0; i < len; i++)
+    {
+      drops[i] = 0;
+      shifts[i] = i;
+    }
+
+  /* look for atlases to drop, and create a mapping of updated texture indices */
+  for (i = cache->atlases->len - 1; i >= 0; i--)
+    {
+      Atlas *atlas = g_ptr_array_index (cache->atlases, i);
+
+      if (atlas->old_pixels > MAX_OLD * atlas->width * atlas->height)
+        {
+          GSK_NOTE(GLYPH_CACHE,
+                   g_print ("Dropping atlas %d (%g.2%% old)\n", i, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height)));
+          g_ptr_array_remove_index (cache->atlases, i);
+
+          drops[i] = 1;
+          for (j = i; j + 1 < len; j++)
+            shifts[j + 1] = shifts[j];
+        }
+    }
+
+  /* no atlas dropped, we're done */
+  if (len == cache->atlases->len)
+    return;
+
+  /* purge glyphs and update texture indices */
+  g_hash_table_iter_init (&iter, cache->hash_table);
+
+  while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+    {
+      if (drops[value->texture_index])
+        {
+          dropped++;
+          g_hash_table_iter_remove (&iter);
+        }
+      else
+        {
+          value->texture_index = shifts[value->texture_index];
+        }
+    }
+
+  GSK_NOTE(GLYPH_CACHE, g_print ("Dropped %d glyphs\n", dropped));
+}
diff --git a/gsk/vulkan/gskvulkanglyphcacheprivate.h b/gsk/vulkan/gskvulkanglyphcacheprivate.h
new file mode 100644 (file)
index 0000000..6cf223f
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
+#define __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
+
+#include <pango/pango.h>
+#include "gskvulkanrendererprivate.h"
+#include "gskvulkanimageprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_GLYPH_CACHE (gsk_vulkan_glyph_cache_get_type ())
+
+G_DECLARE_FINAL_TYPE(GskVulkanGlyphCache, gsk_vulkan_glyph_cache, GSK, VULKAN_GLYPH_CACHE, GObject)
+
+GskVulkanGlyphCache  *gsk_vulkan_glyph_cache_new            (GdkVulkanContext *vulkan);
+
+GskVulkanImage *     gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
+                                                             GskVulkanUploader   *uploader,
+                                                             guint                index);
+
+GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup         (GskVulkanGlyphCache *cache,
+                                                             gboolean             create,
+                                                             PangoFont           *font,
+                                                             PangoGlyph           glyph,
+                                                             float                scale);
+
+void                  gsk_vulkan_glyph_cache_begin_frame    (GskVulkanGlyphCache *cache);
+
+#endif /* __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c
new file mode 100644 (file)
index 0000000..8d3bdb4
--- /dev/null
@@ -0,0 +1,820 @@
+#include "config.h"
+
+#include "gskvulkanimageprivate.h"
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanmemoryprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+#include <string.h>
+
+struct _GskVulkanUploader
+{
+  GdkVulkanContext *vulkan;
+
+  GskVulkanCommandPool *command_pool;
+
+  GArray *before_buffer_barriers;
+  GArray *before_image_barriers;
+  VkCommandBuffer copy_buffer;
+  GArray *after_buffer_barriers;
+  GArray *after_image_barriers;
+
+  GSList *staging_image_free_list;
+  GSList *staging_buffer_free_list;
+};
+
+struct _GskVulkanImage
+{
+  GObject parent_instance;
+
+  GdkVulkanContext *vulkan;
+
+  gsize width;
+  gsize height;
+  VkImageUsageFlags vk_usage;
+  VkImage vk_image;
+  VkImageView vk_image_view;
+  VkImageLayout vk_image_layout;
+  VkAccessFlags vk_access;
+
+  GskVulkanMemory *memory;
+};
+
+G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, G_TYPE_OBJECT)
+
+GskVulkanUploader *
+gsk_vulkan_uploader_new (GdkVulkanContext     *context,
+                         GskVulkanCommandPool *command_pool)
+{
+  GskVulkanUploader *self;
+
+  self = g_slice_new0 (GskVulkanUploader);
+
+  self->vulkan = g_object_ref (context);
+  self->command_pool = command_pool;
+
+  self->before_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
+  self->after_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
+
+  self->before_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
+  self->after_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
+
+  return self;
+}
+
+void
+gsk_vulkan_uploader_free (GskVulkanUploader *self)
+{
+  gsk_vulkan_uploader_reset (self);
+
+  g_array_unref (self->after_buffer_barriers);
+  g_array_unref (self->before_buffer_barriers);
+  g_array_unref (self->after_image_barriers);
+  g_array_unref (self->before_image_barriers);
+
+  g_object_unref (self->vulkan);
+
+  g_slice_free (GskVulkanUploader, self);
+}
+
+static void
+gsk_vulkan_uploader_add_image_barrier (GskVulkanUploader          *self,
+                                       gboolean                    after,
+                                       GskVulkanImage             *image,
+                                       VkImageLayout               new_layout,
+                                       VkAccessFlags               new_access)
+{
+  GArray *array;
+  VkImageMemoryBarrier barrier = {
+    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+    .srcAccessMask = image->vk_access,
+    .dstAccessMask = new_access,
+    .oldLayout = image->vk_image_layout,
+    .newLayout = new_layout,
+    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+    .image = image->vk_image,
+    .subresourceRange = {
+      .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+      .baseMipLevel = 0,
+      .levelCount = 1,
+      .baseArrayLayer = 0,
+      .layerCount = 1
+    }
+  };
+
+  if (after)
+    array = self->after_image_barriers;
+  else
+    array = self->before_image_barriers;
+
+  g_array_append_val (array, barrier);
+
+  image->vk_image_layout = new_layout;
+  image->vk_access = new_access;
+}
+
+static void
+gsk_vulkan_uploader_add_buffer_barrier (GskVulkanUploader           *self,
+                                        gboolean                     after,
+                                        const VkBufferMemoryBarrier *barrier)
+{
+  GArray *array;
+
+  if (after)
+    array = self->after_buffer_barriers;
+  else
+    array = self->before_buffer_barriers;
+
+  g_array_append_val (array, *barrier);
+}
+
+static VkCommandBuffer
+gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self)
+{
+  if (self->copy_buffer == VK_NULL_HANDLE)
+    self->copy_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+
+  return self->copy_buffer;
+}
+
+void
+gsk_vulkan_uploader_upload (GskVulkanUploader *self)
+{
+  if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0)
+    {
+      VkCommandBuffer command_buffer;
+
+      command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+      vkCmdPipelineBarrier (command_buffer,
+                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                            VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
+                            0,
+                            0, NULL,
+                            self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
+                            self->before_image_barriers->len, (VkImageMemoryBarrier *) self->before_image_barriers->data);
+      gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
+      g_array_set_size (self->before_buffer_barriers, 0);
+      g_array_set_size (self->before_image_barriers, 0);
+    }
+
+  /* append these to existing buffer */
+  if (self->after_buffer_barriers->len > 0 || self->after_image_barriers->len > 0)
+    {
+      VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
+      vkCmdPipelineBarrier (command_buffer,
+                            VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
+                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+                            0,
+                            0, NULL,
+                            self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
+                            self->after_image_barriers->len, (VkImageMemoryBarrier *) self->after_image_barriers->data);
+      g_array_set_size (self->after_buffer_barriers, 0);
+      g_array_set_size (self->after_image_barriers, 0);
+    }
+
+  if (self->copy_buffer != VK_NULL_HANDLE)
+    {
+      gsk_vulkan_command_pool_submit_buffer (self->command_pool, self->copy_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
+      self->copy_buffer = VK_NULL_HANDLE;
+    }
+}
+
+void
+gsk_vulkan_uploader_reset (GskVulkanUploader *self)
+{
+  g_array_set_size (self->before_image_barriers, 0);
+  self->copy_buffer = VK_NULL_HANDLE;
+  g_array_set_size (self->after_image_barriers, 0);
+
+  g_slist_free_full (self->staging_image_free_list, g_object_unref);
+  self->staging_image_free_list = NULL;
+  g_slist_free_full (self->staging_buffer_free_list, (GDestroyNotify) gsk_vulkan_buffer_free);
+  self->staging_buffer_free_list = NULL;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new (GdkVulkanContext      *context,
+                      gsize                  width,
+                      gsize                  height,
+                      VkImageTiling          tiling,
+                      VkImageUsageFlags      usage,
+                      VkImageLayout          layout,
+                      VkAccessFlags          access,
+                      VkMemoryPropertyFlags  memory)
+{
+  VkMemoryRequirements requirements;
+  GskVulkanImage *self;
+
+  self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
+
+  self->vulkan = g_object_ref (context);
+  self->width = width;
+  self->height = height;
+  self->vk_usage = usage;
+  self->vk_image_layout = layout;
+  self->vk_access = access;
+
+  GSK_VK_CHECK (vkCreateImage, gdk_vulkan_context_get_device (context),
+                                &(VkImageCreateInfo) {
+                                    .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+                                    .flags = 0,
+                                    .imageType = VK_IMAGE_TYPE_2D,
+                                    .format = VK_FORMAT_B8G8R8A8_UNORM,
+                                    .extent = { width, height, 1 },
+                                    .mipLevels = 1,
+                                    .arrayLayers = 1,
+                                    .samples = VK_SAMPLE_COUNT_1_BIT,
+                                    .tiling = tiling,
+                                    .usage = usage,
+                                    .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+                                    .initialLayout = self->vk_image_layout,
+                                },
+                                NULL,
+                                &self->vk_image);
+
+  vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context),
+                                self->vk_image,
+                                &requirements);
+
+  self->memory = gsk_vulkan_memory_new (context,
+                                        requirements.memoryTypeBits,
+                                        memory,
+                                        requirements.size);
+
+  GSK_VK_CHECK (vkBindImageMemory, gdk_vulkan_context_get_device (context),
+                                   self->vk_image,
+                                   gsk_vulkan_memory_get_device_memory (self->memory),
+                                   0);
+  return self;
+}
+
+static void
+gsk_vulkan_image_upload_data (GskVulkanImage *self,
+                              guchar         *data,
+                              gsize           width,
+                              gsize           height,
+                              gsize           data_stride)
+{
+  VkImageSubresource image_res;
+  VkSubresourceLayout image_layout;
+  gsize mem_stride;
+  guchar *mem;
+
+  image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+  image_res.mipLevel = 0;
+  image_res.arrayLayer = 0;
+
+  mem_stride = width * 4;
+  vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
+                               self->vk_image, &image_res, &image_layout);
+
+  mem = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
+
+  if (image_layout.rowPitch == width * 4 && data_stride == mem_stride)
+    {
+      memcpy (mem, data, data_stride * height);
+    }
+  else
+    {
+      for (gsize i = 0; i < height; i++)
+        {
+          memcpy (mem + i * image_layout.rowPitch, data + i * data_stride, width * 4);
+        }
+    }
+
+  gsk_vulkan_memory_unmap (self->memory);
+}
+
+static void
+gsk_vulkan_image_ensure_view (GskVulkanImage *self,
+                              VkFormat        format)
+{
+  if (self->vk_image_view == VK_NULL_HANDLE)
+    GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
+                                   &(VkImageViewCreateInfo) {
+                                       .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+                                       .image = self->vk_image,
+                                       .viewType = VK_IMAGE_VIEW_TYPE_2D,
+                                       .format = format,
+                                       .components = {
+                                           .r = VK_COMPONENT_SWIZZLE_R,
+                                           .g = VK_COMPONENT_SWIZZLE_G,
+                                           .b = VK_COMPONENT_SWIZZLE_B,
+                                           .a = VK_COMPONENT_SWIZZLE_A,
+                                       },
+                                       .subresourceRange = {
+                                           .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                           .baseMipLevel = 0,
+                                           .levelCount = 1,
+                                           .baseArrayLayer = 0,
+                                           .layerCount = 1,
+                                       },
+                                   },
+                                   NULL,
+                                   &self->vk_image_view);
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_via_staging_buffer (GskVulkanUploader *uploader,
+                                                   guchar            *data,
+                                                   gsize              width,
+                                                   gsize              height,
+                                                   gsize              stride)
+{
+  GskVulkanImage *self;
+  GskVulkanBuffer *staging;
+  gsize buffer_size = width * height * 4;
+  guchar *mem;
+
+  staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
+  mem = gsk_vulkan_buffer_map (staging);
+
+  if (stride == width * 4)
+    {
+      memcpy (mem, data, stride * height);
+    }
+  else
+    {
+      for (gsize i = 0; i < height; i++)
+        {
+          memcpy (mem + i * width * 4, data + i * stride, width * 4);
+        }
+    }
+
+  gsk_vulkan_buffer_unmap (staging);
+
+  gsk_vulkan_uploader_add_buffer_barrier (uploader,
+                                          FALSE,
+                                          &(VkBufferMemoryBarrier) {
+                                             .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+                                             .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
+                                             .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+                                             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .buffer = gsk_vulkan_buffer_get_buffer(staging),
+                                             .offset = 0,
+                                             .size = buffer_size,
+                                         });
+
+  self = gsk_vulkan_image_new (uploader->vulkan,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                               VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_IMAGE_LAYOUT_UNDEFINED,
+                               VK_ACCESS_TRANSFER_WRITE_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                         VK_ACCESS_TRANSFER_WRITE_BIT);
+
+  vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                          gsk_vulkan_buffer_get_buffer (staging),
+                          self->vk_image,
+                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                          1,
+                          (VkBufferImageCopy[1]) {
+                               {
+                                   .bufferOffset = 0,
+                                   .imageSubresource = {
+                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                       .mipLevel = 0,
+                                       .baseArrayLayer = 0,
+                                       .layerCount = 1
+                                   },
+                                   .imageOffset = { 0, 0, 0 },
+                                   .imageExtent = {
+                                       .width = width,
+                                       .height = height,
+                                       .depth = 1
+                                   }
+                               }
+                          });
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         TRUE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                         VK_ACCESS_SHADER_READ_BIT);
+
+  uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_via_staging_image (GskVulkanUploader *uploader,
+                                                  guchar            *data,
+                                                  gsize              width,
+                                                  gsize              height,
+                                                  gsize              stride)
+{
+  GskVulkanImage *self, *staging;
+
+  staging = gsk_vulkan_image_new (uploader->vulkan,
+                                  width,
+                                  height,
+                                  VK_IMAGE_TILING_LINEAR,
+                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+                                  VK_IMAGE_LAYOUT_PREINITIALIZED,
+                                  VK_ACCESS_TRANSFER_WRITE_BIT,
+                                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+
+  gsk_vulkan_image_upload_data (staging, data, width, height, stride);
+
+  self = gsk_vulkan_image_new (uploader->vulkan,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                               VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_IMAGE_LAYOUT_UNDEFINED,
+                               VK_ACCESS_TRANSFER_WRITE_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         staging,
+                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                                         VK_ACCESS_TRANSFER_READ_BIT);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                         VK_ACCESS_TRANSFER_WRITE_BIT);
+
+  vkCmdCopyImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                  staging->vk_image,
+                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                  self->vk_image,
+                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                  1,
+                  &(VkImageCopy) {
+                      .srcSubresource = {
+                          .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                          .mipLevel = 0,
+                          .baseArrayLayer = 0,
+                          .layerCount = 1
+                      },
+                      .srcOffset = { 0, 0, 0 },
+                      .dstSubresource = {
+                          .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                          .mipLevel = 0,
+                          .baseArrayLayer = 0,
+                          .layerCount = 1
+                      },
+                      .dstOffset = { 0, 0, 0 },
+                      .extent = {
+                          .width = width,
+                          .height = height,
+                          .depth = 1
+                      }
+                  });
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         TRUE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                         VK_ACCESS_SHADER_READ_BIT);
+
+  uploader->staging_image_free_list = g_slist_prepend (uploader->staging_image_free_list, staging);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_directly (GskVulkanUploader *uploader,
+                                         guchar            *data,
+                                         gsize              width,
+                                         gsize              height,
+                                         gsize              stride)
+{
+  GskVulkanImage *self;
+
+  self = gsk_vulkan_image_new (uploader->vulkan,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_LINEAR,
+                               VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_IMAGE_LAYOUT_PREINITIALIZED,
+                               VK_ACCESS_HOST_WRITE_BIT,
+                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+
+  gsk_vulkan_image_upload_data (self, data, width, height, stride);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         TRUE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                         VK_ACCESS_SHADER_READ_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
+                                guchar            *data,
+                                gsize              width,
+                                gsize              height,
+                                gsize              stride)
+{
+  if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
+    return gsk_vulkan_image_new_from_data_via_staging_buffer (uploader, data, width, height, stride);
+  if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
+    return gsk_vulkan_image_new_from_data_via_staging_image (uploader, data, width, height, stride);
+  else
+    return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
+                                    VkImage           image,
+                                    VkFormat          format,
+                                    gsize             width,
+                                    gsize             height)
+{
+  GskVulkanImage *self;
+
+  self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
+
+  self->vulkan = g_object_ref (context);
+  self->width = width;
+  self->height = height;
+  self->vk_image = image;
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
+                                      gsize             width,
+                                      gsize             height)
+{
+  GskVulkanImage *self;
+
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
+                                gsize             width,
+                                gsize             height)
+{
+  GskVulkanImage *self;
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_IMAGE_LAYOUT_UNDEFINED,
+                               0,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
+                                  gsize             width,
+                                  gsize             height)
+{
+  GskVulkanImage *self;
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                               VK_IMAGE_USAGE_SAMPLED_BIT |
+                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+                               VK_IMAGE_LAYOUT_UNDEFINED,
+                               0,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+GdkTexture *
+gsk_vulkan_image_download (GskVulkanImage    *self,
+                           GskVulkanUploader *uploader)
+{
+  GskVulkanBuffer *buffer;
+  GdkTexture *texture;
+  guchar *mem;
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                                         VK_ACCESS_TRANSFER_READ_BIT);
+
+  buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
+
+  vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                          self->vk_image,
+                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                          gsk_vulkan_buffer_get_buffer (buffer),
+                          1,
+                          (VkBufferImageCopy[1]) {
+                               {
+                                   .bufferOffset = 0,
+                                   .imageSubresource = {
+                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                       .mipLevel = 0,
+                                       .baseArrayLayer = 0,
+                                       .layerCount = 1
+                                   },
+                                   .imageOffset = { 0, 0, 0 },
+                                   .imageExtent = {
+                                       .width = self->width,
+                                       .height = self->height,
+                                       .depth = 1
+                                   }
+                               }
+                          });
+
+  gsk_vulkan_uploader_upload (uploader);
+
+  GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
+
+  mem = gsk_vulkan_buffer_map (buffer);
+  texture = gdk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
+  gsk_vulkan_buffer_unmap (buffer);
+  gsk_vulkan_buffer_free (buffer);
+
+  return texture;
+}
+
+void
+gsk_vulkan_image_upload_regions (GskVulkanImage    *self,
+                                 GskVulkanUploader *uploader,
+                                 guint              num_regions,
+                                 GskImageRegion    *regions)
+{
+  GskVulkanBuffer *staging;
+  guchar *mem;
+  guchar *m;
+  gsize size;
+  gsize offset;
+  VkBufferImageCopy *bufferImageCopy;
+
+  size = 0;
+  for (int i = 0; i < num_regions; i++)
+    size += regions[i].width * regions[i].height * 4;
+
+  staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size);
+  mem = gsk_vulkan_buffer_map (staging);
+
+  bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
+  memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
+
+  offset = 0;
+  for (int i = 0; i < num_regions; i++)
+    {
+      m = mem + offset;
+      if (regions[i].stride == regions[i].width * 4)
+        {
+          memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
+        }
+      else
+        {
+          for (gsize r = 0; r < regions[i].height; i++)
+            memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
+        }
+
+      bufferImageCopy[i].bufferOffset = offset;
+      bufferImageCopy[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+      bufferImageCopy[i].imageSubresource.mipLevel = 0;
+      bufferImageCopy[i].imageSubresource.baseArrayLayer = 0;
+      bufferImageCopy[i].imageSubresource.layerCount = 1;
+      bufferImageCopy[i].imageOffset.x = regions[i].x;
+      bufferImageCopy[i].imageOffset.y = regions[i].y;
+      bufferImageCopy[i].imageOffset.z = 0;
+      bufferImageCopy[i].imageExtent.width = regions[i].width;
+      bufferImageCopy[i].imageExtent.height = regions[i].height;
+      bufferImageCopy[i].imageExtent.depth = 1;
+
+      offset += regions[i].width * regions[i].height * 4;
+    }
+
+  gsk_vulkan_buffer_unmap (staging);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                         VK_ACCESS_TRANSFER_WRITE_BIT);
+
+  vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                          gsk_vulkan_buffer_get_buffer (staging),
+                          self->vk_image,
+                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                          num_regions,
+                          bufferImageCopy);
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         TRUE,
+                                         self,
+                                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                         VK_ACCESS_SHADER_READ_BIT);
+
+  uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+}
+
+static void
+gsk_vulkan_image_finalize (GObject *object)
+{
+  GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
+
+  if (self->vk_image_view != VK_NULL_HANDLE)
+    {
+      vkDestroyImageView (gdk_vulkan_context_get_device (self->vulkan),
+                          self->vk_image_view,
+                          NULL);
+    }
+
+  /* memory is NULL for for_swapchain() images, where we don't own
+   * the VkImage */
+  if (self->memory)
+    {
+      vkDestroyImage (gdk_vulkan_context_get_device (self->vulkan),
+                      self->vk_image,
+                      NULL);
+
+      gsk_vulkan_memory_free (self->memory);
+    }
+
+  g_object_unref (self->vulkan);
+
+  G_OBJECT_CLASS (gsk_vulkan_image_parent_class)->finalize (object);
+}
+
+static void
+gsk_vulkan_image_class_init (GskVulkanImageClass *klass)
+{
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_image_finalize;
+}
+
+static void
+gsk_vulkan_image_init (GskVulkanImage *self)
+{
+}
+
+gsize
+gsk_vulkan_image_get_width (GskVulkanImage *self)
+{
+  return self->width;
+}
+
+gsize
+gsk_vulkan_image_get_height (GskVulkanImage *self)
+{
+  return self->height;
+}
+
+VkImage
+gsk_vulkan_image_get_image (GskVulkanImage *self)
+{
+  return self->vk_image;
+}
+
+VkImageView
+gsk_vulkan_image_get_image_view (GskVulkanImage *self)
+{
+  return self->vk_image_view;
+}
diff --git a/gsk/vulkan/gskvulkanimageprivate.h b/gsk/vulkan/gskvulkanimageprivate.h
new file mode 100644 (file)
index 0000000..e775fe0
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __GSK_VULKAN_IMAGE_PRIVATE_H__
+#define __GSK_VULKAN_IMAGE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#include "gskvulkancommandpoolprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanUploader GskVulkanUploader;
+
+#define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanImage, gsk_vulkan_image, GSK, VULKAN_IMAGE, GObject)
+
+GskVulkanUploader *     gsk_vulkan_uploader_new                         (GdkVulkanContext       *context,
+                                                                         GskVulkanCommandPool   *command_pool);
+void                    gsk_vulkan_uploader_free                        (GskVulkanUploader      *self);
+
+void                    gsk_vulkan_uploader_reset                       (GskVulkanUploader      *self);
+void                    gsk_vulkan_uploader_upload                      (GskVulkanUploader      *self);
+
+GskVulkanImage *        gsk_vulkan_image_new_for_swapchain              (GdkVulkanContext       *context,
+                                                                         VkImage                 image,
+                                                                         VkFormat                format,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+GskVulkanImage *        gsk_vulkan_image_new_from_data                  (GskVulkanUploader      *uploader,
+                                                                         guchar                 *data,
+                                                                         gsize                   width,
+                                                                         gsize                   height,
+                                                                         gsize                   stride);
+
+typedef struct {
+  guchar *data;
+  gsize width;
+  gsize height;
+  gsize stride;
+  gsize x;
+  gsize y;
+} GskImageRegion;
+
+void                    gsk_vulkan_image_upload_regions                 (GskVulkanImage         *image,
+                                                                         GskVulkanUploader      *uploader,
+                                                                         guint                   num_regions,
+                                                                         GskImageRegion         *regions);
+GskVulkanImage *        gsk_vulkan_image_new_for_framebuffer            (GdkVulkanContext       *context,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+GskVulkanImage *        gsk_vulkan_image_new_for_atlas                  (GdkVulkanContext       *context,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+GskVulkanImage *        gsk_vulkan_image_new_for_texture                (GdkVulkanContext       *context,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+
+GdkTexture *            gsk_vulkan_image_download                       (GskVulkanImage         *self,
+                                                                         GskVulkanUploader      *uploader);
+
+gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
+gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
+VkImage                 gsk_vulkan_image_get_image                      (GskVulkanImage         *self);
+VkImageView             gsk_vulkan_image_get_image_view                 (GskVulkanImage         *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_IMAGE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanlineargradientpipeline.c b/gsk/vulkan/gskvulkanlineargradientpipeline.c
new file mode 100644 (file)
index 0000000..058a2f8
--- /dev/null
@@ -0,0 +1,225 @@
+#include "config.h"
+
+#include "gskvulkanlineargradientpipelineprivate.h"
+
+struct _GskVulkanLinearGradientPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance;
+
+struct _GskVulkanLinearGradientInstance
+{
+  float rect[4];
+  float start[2];
+  float end[2];
+  gint32 repeating;
+  gint32 stop_count;
+  float offsets[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS];
+  float colors[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS][4];
+};
+
+G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanLinearGradientInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end),
+      },
+      {
+          .location = 3,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SINT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating),
+      },
+      {
+          .location = 4,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SINT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count),
+      },
+      {
+          .location = 5,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets),
+      },
+      {
+          .location = 6,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets) + sizeof (float) * 4,
+      },
+      {
+          .location = 7,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[0]),
+      },
+      {
+          .location = 8,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[1]),
+      },
+      {
+          .location = 9,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[2]),
+      },
+      {
+          .location = 10,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[3]),
+      },
+      {
+          .location = 11,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[4]),
+      },
+      {
+          .location = 12,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[5]),
+      },
+      {
+          .location = 13,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[6]),
+      },
+      {
+          .location = 14,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[7]),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanLinearGradientPipeline *self = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_linear_gradient_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_class_init (GskVulkanLinearGradientPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_linear_gradient_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_init (GskVulkanLinearGradientPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext        *context,
+                                         VkPipelineLayout         layout,
+                                         const char              *shader_name,
+                                         VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GskVulkanLinearGradientPipeline *pipeline)
+{
+  return sizeof (GskVulkanLinearGradientInstance);
+}
+
+void
+gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline,
+                                                         guchar                    *data,
+                                                         const graphene_rect_t     *rect,
+                                                         const graphene_point_t    *start,
+                                                         const graphene_point_t    *end,
+                                                         gboolean                   repeating,
+                                                         gsize                      n_stops,
+                                                         const GskColorStop        *stops)
+{
+  GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data;
+  gsize i;
+
+  if (n_stops > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
+    {
+      g_warning ("Only %u color stops supported.", GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
+      n_stops = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS;
+    }
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+  instance->start[0] = start->x;
+  instance->start[1] = start->y;
+  instance->end[0] = end->x;
+  instance->end[1] = end->y;
+  instance->repeating = repeating;
+  instance->stop_count = n_stops;
+  for (i = 0; i < n_stops; i++)
+    {
+      instance->offsets[i] = stops[i].offset;
+      instance->colors[i][0] = stops[i].color.red;
+      instance->colors[i][1] = stops[i].color.green;
+      instance->colors[i][2] = stops[i].color.blue;
+      instance->colors[i][3] = stops[i].color.alpha;
+    }
+}
+
+gsize
+gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline *pipeline,
+                                   VkCommandBuffer            command_buffer,
+                                   gsize                      offset,
+                                   gsize                      n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h b/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h
new file mode 100644 (file)
index 0000000..71b6559
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskrendernode.h"
+
+G_BEGIN_DECLS
+
+#define GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS 8
+
+typedef struct _GskVulkanLinearGradientPipelineLayout GskVulkanLinearGradientPipelineLayout;
+
+#define GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE (gsk_vulkan_linear_gradient_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK, VULKAN_LINEAR_GRADIENT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_linear_gradient_pipeline_new         (GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+
+gsize                   gsk_vulkan_linear_gradient_pipeline_count_vertex_data
+                                                                        (GskVulkanLinearGradientPipeline*pipeline);
+void                    gsk_vulkan_linear_gradient_pipeline_collect_vertex_data
+                                                                        (GskVulkanLinearGradientPipeline*pipeline,
+                                                                         guchar                         *data,
+                                                                         const graphene_rect_t          *rect,
+                                                                         const graphene_point_t         *start,
+                                                                         const graphene_point_t         *end,
+                                                                         gboolean                        repeating,
+                                                                         gsize                           n_stops,
+                                                                         const GskColorStop             *stops);
+gsize                   gsk_vulkan_linear_gradient_pipeline_draw        (GskVulkanLinearGradientPipeline*pipeline,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         gsize                           offset,
+                                                                         gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanmemory.c b/gsk/vulkan/gskvulkanmemory.c
new file mode 100644 (file)
index 0000000..1ff4675
--- /dev/null
@@ -0,0 +1,95 @@
+#include "config.h"
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanmemoryprivate.h"
+
+struct _GskVulkanMemory
+{
+  GdkVulkanContext *vulkan;
+
+  gsize size;
+
+  VkDeviceMemory vk_memory;
+};
+
+GskVulkanMemory *
+gsk_vulkan_memory_new (GdkVulkanContext      *context,
+                       uint32_t               allowed_types,
+                       VkMemoryPropertyFlags  flags,
+                       gsize                  size)
+{
+  VkPhysicalDeviceMemoryProperties properties;
+  GskVulkanMemory *self;
+  uint32_t i;
+
+  self = g_slice_new0 (GskVulkanMemory);
+
+  self->vulkan = g_object_ref (context);
+  self->size = size;
+
+  vkGetPhysicalDeviceMemoryProperties (gdk_vulkan_context_get_physical_device (context),
+                                       &properties);
+
+  for (i = 0; i < properties.memoryTypeCount; i++)
+    {
+      if (!(allowed_types & (1 << i)))
+        continue;
+
+      if ((properties.memoryTypes[i].propertyFlags & flags) == flags)
+        break;
+  }
+
+  g_assert (i < properties.memoryTypeCount);
+
+  GSK_VK_CHECK (vkAllocateMemory, gdk_vulkan_context_get_device (context),
+                                  &(VkMemoryAllocateInfo) {
+                                      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+                                      .allocationSize = size,
+                                      .memoryTypeIndex = i
+                                  },
+                                  NULL,
+                                  &self->vk_memory);
+
+  return self;
+}
+
+void
+gsk_vulkan_memory_free (GskVulkanMemory *self)
+{
+  vkFreeMemory (gdk_vulkan_context_get_device (self->vulkan),
+                self->vk_memory,
+                NULL);
+
+  g_object_unref (self->vulkan);
+
+  g_slice_free (GskVulkanMemory, self);
+}
+
+VkDeviceMemory
+gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self)
+{
+  return self->vk_memory;
+}
+
+guchar *
+gsk_vulkan_memory_map (GskVulkanMemory *self)
+{
+  void *data;
+
+  GSK_VK_CHECK (vkMapMemory, gdk_vulkan_context_get_device (self->vulkan),
+                             self->vk_memory,
+                             0,
+                             self->size,
+                             0,
+                             &data);
+
+  return data;
+}
+
+void
+gsk_vulkan_memory_unmap (GskVulkanMemory *self)
+{
+  vkUnmapMemory (gdk_vulkan_context_get_device (self->vulkan),
+                 self->vk_memory);
+}
+
diff --git a/gsk/vulkan/gskvulkanmemoryprivate.h b/gsk/vulkan/gskvulkanmemoryprivate.h
new file mode 100644 (file)
index 0000000..010c133
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__
+#define __GSK_VULKAN_MEMORY_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanMemory GskVulkanMemory;
+
+GskVulkanMemory *       gsk_vulkan_memory_new                           (GdkVulkanContext       *context,
+                                                                         uint32_t                allowed_types,
+                                                                         VkMemoryPropertyFlags   properties,
+                                                                         gsize                   size);
+void                    gsk_vulkan_memory_free                          (GskVulkanMemory        *memory);
+
+VkDeviceMemory          gsk_vulkan_memory_get_device_memory             (GskVulkanMemory        *self);
+
+guchar *                gsk_vulkan_memory_map                           (GskVulkanMemory        *self);
+void                    gsk_vulkan_memory_unmap                         (GskVulkanMemory        *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_MEMORY_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanpipeline.c b/gsk/vulkan/gskvulkanpipeline.c
new file mode 100644 (file)
index 0000000..38d5a57
--- /dev/null
@@ -0,0 +1,189 @@
+#include "config.h"
+
+#include "gskvulkanpipelineprivate.h"
+
+#include "gskvulkanpushconstantsprivate.h"
+#include "gskvulkanshaderprivate.h"
+
+#include <graphene.h>
+
+typedef struct _GskVulkanPipelinePrivate GskVulkanPipelinePrivate;
+
+struct _GskVulkanPipelinePrivate
+{
+  GObject parent_instance;
+
+  GdkVulkanContext *context;
+
+  VkPipeline pipeline;
+  VkPipelineLayout layout;
+
+  GskVulkanShader *vertex_shader;
+  GskVulkanShader *fragment_shader;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT)
+
+static void
+gsk_vulkan_pipeline_finalize (GObject *gobject)
+{
+  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (GSK_VULKAN_PIPELINE (gobject));
+  VkDevice device;
+
+  device = gdk_vulkan_context_get_device (priv->context);
+
+  vkDestroyPipeline (device,
+                     priv->pipeline,
+                     NULL);
+
+  g_clear_pointer (&priv->fragment_shader, gsk_vulkan_shader_free);
+  g_clear_pointer (&priv->vertex_shader, gsk_vulkan_shader_free);
+
+  G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_pipeline_class_init (GskVulkanPipelineClass *klass)
+{
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_pipeline_finalize;
+}
+
+static void
+gsk_vulkan_pipeline_init (GskVulkanPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_pipeline_new (GType                    pipeline_type,
+                         GdkVulkanContext        *context,
+                         VkPipelineLayout         layout,
+                         const char              *shader_name,
+                         VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
+                                       VK_BLEND_FACTOR_ONE,
+                                       VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+GskVulkanPipeline *
+gsk_vulkan_pipeline_new_full (GType                    pipeline_type,
+                              GdkVulkanContext        *context,
+                              VkPipelineLayout         layout,
+                              const char              *shader_name,
+                              VkRenderPass             render_pass,
+                              VkBlendFactor            srcBlendFactor,
+                              VkBlendFactor            dstBlendFactor)
+{
+  GskVulkanPipelinePrivate *priv;
+  GskVulkanPipeline *self;
+  VkDevice device;
+
+  g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
+  g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
+  g_return_val_if_fail (shader_name != NULL, NULL);
+  g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
+
+  self = g_object_new (pipeline_type, NULL);
+
+  priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+  device = gdk_vulkan_context_get_device (context);
+
+  priv->context = context;
+  priv->layout = layout;
+
+  priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
+  priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
+
+  GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
+                                           VK_NULL_HANDLE,
+                                           1,
+                                           &(VkGraphicsPipelineCreateInfo) {
+                                               .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+                                               .stageCount = 2,
+                                               .pStages = (VkPipelineShaderStageCreateInfo[2]) {
+                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
+                                                   GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
+                                               },
+                                               .pVertexInputState = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self),
+                                               .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+                                                   .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+                                                   .primitiveRestartEnable = VK_FALSE,
+                                               },
+                                               .pTessellationState = NULL,
+                                               .pViewportState = &(VkPipelineViewportStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+                                                   .viewportCount = 1,
+                                                   .scissorCount = 1
+                                               },
+                                               .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+                                                   .depthClampEnable = VK_FALSE,
+                                                   .rasterizerDiscardEnable = VK_FALSE,
+                                                   .polygonMode = VK_POLYGON_MODE_FILL,
+                                                   .cullMode = VK_CULL_MODE_BACK_BIT,
+                                                   .frontFace = VK_FRONT_FACE_CLOCKWISE,
+                                                   .lineWidth = 1.0f,
+                                               },
+                                               .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+                                                   .rasterizationSamples = 1,
+                                               },
+                                               .pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
+                                               },
+                                               .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+                                                   .attachmentCount = 1,
+                                                   .pAttachments = (VkPipelineColorBlendAttachmentState []) {
+                                                       {
+                                                           .blendEnable = VK_TRUE,
+                                                           .colorBlendOp = VK_BLEND_OP_ADD,
+                                                           .srcColorBlendFactor = srcBlendFactor,
+                                                           .dstColorBlendFactor = dstBlendFactor,
+                                                           .alphaBlendOp = VK_BLEND_OP_ADD,
+                                                           .srcAlphaBlendFactor = srcBlendFactor,
+                                                           .dstAlphaBlendFactor = dstBlendFactor,
+                                                           .colorWriteMask = VK_COLOR_COMPONENT_A_BIT
+                                                                           | VK_COLOR_COMPONENT_R_BIT
+                                                                           | VK_COLOR_COMPONENT_G_BIT
+                                                                           | VK_COLOR_COMPONENT_B_BIT
+                                                       },
+                                                   }
+                                               },
+                                               .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
+                                                   .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+                                                   .dynamicStateCount = 2,
+                                                   .pDynamicStates = (VkDynamicState[2]) {
+                                                       VK_DYNAMIC_STATE_VIEWPORT,
+                                                       VK_DYNAMIC_STATE_SCISSOR
+                                                   },
+                                               },
+                                               .layout = priv->layout,
+                                               .renderPass = render_pass,
+                                               .subpass = 0,
+                                               .basePipelineHandle = VK_NULL_HANDLE,
+                                               .basePipelineIndex = -1,
+                                           },
+                                           NULL,
+                                           &priv->pipeline);
+
+  return self;
+}
+
+VkPipeline
+gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self)
+{
+  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+  return priv->pipeline;
+}
+
+VkPipelineLayout
+gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self)
+{
+  GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+  return priv->layout;
+}
diff --git a/gsk/vulkan/gskvulkanpipelineprivate.h b/gsk/vulkan/gskvulkanpipelineprivate.h
new file mode 100644 (file)
index 0000000..cd41f82
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_PIPELINE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#include "gskdebugprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_PIPELINE (gsk_vulkan_pipeline_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, GSK, VULKAN_PIPELINE, GObject)
+
+struct _GskVulkanPipelineClass
+{
+  GObjectClass parent_class;
+
+  const VkPipelineVertexInputStateCreateInfo *
+                                (* get_input_state_create_info)         (GskVulkanPipeline              *self);
+};
+
+static inline VkResult
+gsk_vulkan_handle_result (VkResult    res,
+                          const char *called_function)
+{
+  if (res != VK_SUCCESS)
+    {
+      GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res));
+    }
+  return res;
+}
+
+#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
+
+GskVulkanPipeline *     gsk_vulkan_pipeline_new                         (GType                           pipeline_type,
+                                                                         GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass);
+GskVulkanPipeline *     gsk_vulkan_pipeline_new_full                    (GType                           pipeline_type,
+                                                                         GdkVulkanContext               *context,
+                                                                         VkPipelineLayout                layout,
+                                                                         const char                     *shader_name,
+                                                                         VkRenderPass                    render_pass,
+                                                                         VkBlendFactor                   srcBlendFactor,
+                                                                         VkBlendFactor                   dstBlendFactor);
+
+VkPipeline              gsk_vulkan_pipeline_get_pipeline                (GskVulkanPipeline              *self);
+VkPipelineLayout        gsk_vulkan_pipeline_get_pipeline_layout         (GskVulkanPipeline              *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanpushconstants.c b/gsk/vulkan/gskvulkanpushconstants.c
new file mode 100644 (file)
index 0000000..dc4ae40
--- /dev/null
@@ -0,0 +1,114 @@
+#include "config.h"
+
+#include "gskvulkanpushconstantsprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+typedef struct _GskVulkanPushConstantsWire GskVulkanPushConstantsWire;
+
+struct _GskVulkanPushConstantsWire
+{
+  struct {
+    float mvp[16];
+    float clip[12];
+  } common;
+};
+
+void
+gsk_vulkan_push_constants_init (GskVulkanPushConstants  *constants,
+                                const graphene_matrix_t *mvp,
+                                const graphene_rect_t   *viewport)
+{
+  graphene_matrix_init_from_matrix (&constants->mvp, mvp);
+  gsk_vulkan_clip_init_empty (&constants->clip, viewport);
+}
+
+void
+gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants       *self,
+                                     const GskVulkanPushConstants *src)
+{
+  *self = *src;
+}
+
+gboolean
+gsk_vulkan_push_constants_transform (GskVulkanPushConstants       *self,
+                                     const GskVulkanPushConstants *src,
+                                     const graphene_matrix_t      *transform,
+                                     const graphene_rect_t        *viewport)
+
+{
+  if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
+    return FALSE;
+
+  graphene_matrix_multiply (transform, &src->mvp, &self->mvp);
+  return TRUE;
+}
+
+gboolean
+gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants       *self,
+                                          const GskVulkanPushConstants *src,
+                                          const graphene_rect_t        *rect)
+{
+  if (!gsk_vulkan_clip_intersect_rect (&self->clip, &src->clip, rect))
+    return FALSE;
+
+  graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
+  return TRUE;
+}
+
+gboolean
+gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants       *self,
+                                             const GskVulkanPushConstants *src,
+                                             const GskRoundedRect         *rect)
+{
+  if (!gsk_vulkan_clip_intersect_rounded_rect (&self->clip, &src->clip, rect))
+    return FALSE;
+
+  graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
+  return TRUE;
+}
+
+static void
+gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire   *wire,
+                                     const GskVulkanPushConstants *self)
+{
+  graphene_matrix_to_float (&self->mvp, wire->common.mvp);
+  gsk_rounded_rect_to_float (&self->clip.rect, wire->common.clip);
+}
+
+void
+gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
+                                VkCommandBuffer               command_buffer,
+                                VkPipelineLayout              pipeline_layout)
+{
+  GskVulkanPushConstantsWire wire;
+
+  gsk_vulkan_push_constants_wire_init (&wire, self);
+
+  vkCmdPushConstants (command_buffer,
+                      pipeline_layout,
+                      VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+                      G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
+                      sizeof (wire.common),
+                      &wire.common);
+}
+
+uint32_t
+gsk_vulkan_push_constants_get_range_count (void)
+{
+  return 1;
+}
+
+const VkPushConstantRange *
+gsk_vulkan_push_constants_get_ranges (void)
+{
+  static const VkPushConstantRange ranges[1] = {
+      {
+          .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+          .offset = G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
+          .size = sizeof (((GskVulkanPushConstantsWire *) 0)->common)
+      }
+  };
+
+  return ranges;
+}
diff --git a/gsk/vulkan/gskvulkanpushconstantsprivate.h b/gsk/vulkan/gskvulkanpushconstantsprivate.h
new file mode 100644 (file)
index 0000000..897d9c6
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
+#define __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <graphene.h>
+#include "gskvulkanclipprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanPushConstants GskVulkanPushConstants;
+
+struct _GskVulkanPushConstants
+{
+  graphene_matrix_t mvp;
+  GskVulkanClip clip;
+};
+
+const VkPushConstantRange *
+                        gsk_vulkan_push_constants_get_ranges            (void) G_GNUC_PURE;
+uint32_t                gsk_vulkan_push_constants_get_range_count       (void) G_GNUC_PURE;
+
+void                    gsk_vulkan_push_constants_init                  (GskVulkanPushConstants         *constants,
+                                                                         const graphene_matrix_t        *mvp,
+                                                                         const graphene_rect_t          *viewport);
+void                    gsk_vulkan_push_constants_init_copy             (GskVulkanPushConstants         *self,
+                                                                         const GskVulkanPushConstants   *src);
+
+gboolean                gsk_vulkan_push_constants_transform             (GskVulkanPushConstants         *self,
+                                                                         const GskVulkanPushConstants   *src,
+                                                                         const graphene_matrix_t        *transform,
+                                                                         const graphene_rect_t          *viewport);
+gboolean                gsk_vulkan_push_constants_intersect_rect        (GskVulkanPushConstants         *self,
+                                                                         const GskVulkanPushConstants   *src,
+                                                                         const graphene_rect_t          *rect);
+gboolean                gsk_vulkan_push_constants_intersect_rounded     (GskVulkanPushConstants         *self,
+                                                                         const GskVulkanPushConstants   *src,
+                                                                         const GskRoundedRect           *rect);
+
+void                    gsk_vulkan_push_constants_push                  (const GskVulkanPushConstants   *self,
+                                                                         VkCommandBuffer                 command_buffer,
+                                                                         VkPipelineLayout                pipeline_layout);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanrender.c b/gsk/vulkan/gskvulkanrender.c
new file mode 100644 (file)
index 0000000..5d8b241
--- /dev/null
@@ -0,0 +1,761 @@
+#include "config.h"
+
+#include "gskprivate.h"
+
+#include "gskvulkanrenderprivate.h"
+
+#include "gskrendererprivate.h"
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkancommandpoolprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderpassprivate.h"
+
+#include "gskvulkanblendmodepipelineprivate.h"
+#include "gskvulkanblurpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
+#include "gskvulkanboxshadowpipelineprivate.h"
+#include "gskvulkancolorpipelineprivate.h"
+#include "gskvulkancolortextpipelineprivate.h"
+#include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkaneffectpipelineprivate.h"
+#include "gskvulkanlineargradientpipelineprivate.h"
+#include "gskvulkantextpipelineprivate.h"
+#include "gskvulkantexturepipelineprivate.h"
+#include "gskvulkanpushconstantsprivate.h"
+
+#define DESCRIPTOR_POOL_MAXSETS 128
+#define DESCRIPTOR_POOL_MAXSETS_INCREASE 128
+
+struct _GskVulkanRender
+{
+  GskRenderer *renderer;
+  GdkVulkanContext *vulkan;
+
+  int scale_factor;
+  graphene_rect_t viewport;
+  cairo_region_t *clip;
+
+  GHashTable *framebuffers;
+  GskVulkanCommandPool *command_pool;
+  VkFence fence;
+  VkRenderPass render_pass;
+  VkDescriptorSetLayout descriptor_set_layout;
+  VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
+  GskVulkanUploader *uploader;
+
+  GHashTable *descriptor_set_indexes;
+  VkDescriptorPool descriptor_pool;
+  uint32_t descriptor_pool_maxsets;
+  VkDescriptorSet *descriptor_sets;
+  gsize n_descriptor_sets;
+  GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES];
+
+  GskVulkanImage *target;
+
+  VkSampler sampler;
+  VkSampler repeating_sampler;
+
+  GList *render_passes;
+  GSList *cleanup_images;
+
+  GQuark render_pass_counter;
+  GQuark gpu_time_timer;
+};
+
+static void
+gsk_vulkan_render_setup (GskVulkanRender       *self,
+                         GskVulkanImage        *target,
+                         const graphene_rect_t *rect)
+{
+  GdkWindow *window = gsk_renderer_get_window (self->renderer);
+
+  self->target = g_object_ref (target);
+
+  if (rect)
+    {
+      self->viewport = *rect;
+      self->scale_factor = 1;
+      self->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+                                                      0, 0,
+                                                      gsk_vulkan_image_get_width (target),
+                                                      gsk_vulkan_image_get_height (target)
+                                                  });
+    }
+  else
+    {
+      self->scale_factor = gdk_window_get_scale_factor (gsk_renderer_get_window (self->renderer));
+      self->viewport = GRAPHENE_RECT_INIT (0, 0,
+                                           gdk_window_get_width (window) * self->scale_factor,
+                                           gdk_window_get_height (window) * self->scale_factor);
+      self->clip = gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer));
+    }
+}
+
+static guint desc_set_index_hash (gconstpointer v);
+static gboolean desc_set_index_equal (gconstpointer v1, gconstpointer v2);
+
+GskVulkanRender *
+gsk_vulkan_render_new (GskRenderer      *renderer,
+                       GdkVulkanContext *context)
+{
+  GskVulkanRender *self;
+  VkDevice device;
+
+  self = g_slice_new0 (GskVulkanRender);
+
+  self->vulkan = context;
+  self->renderer = renderer;
+  self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
+  self->descriptor_set_indexes = g_hash_table_new_full (desc_set_index_hash, desc_set_index_equal, NULL, g_free);
+
+  device = gdk_vulkan_context_get_device (self->vulkan);
+
+  self->command_pool = gsk_vulkan_command_pool_new (self->vulkan);
+  GSK_VK_CHECK (vkCreateFence, device,
+                               &(VkFenceCreateInfo) {
+                                   .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+                                   .flags = VK_FENCE_CREATE_SIGNALED_BIT
+                               },
+                               NULL,
+                               &self->fence);
+
+  self->descriptor_pool_maxsets = DESCRIPTOR_POOL_MAXSETS;
+  GSK_VK_CHECK (vkCreateDescriptorPool, device,
+                                        &(VkDescriptorPoolCreateInfo) {
+                                            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+                                            .maxSets = self->descriptor_pool_maxsets,
+                                            .poolSizeCount = 1,
+                                            .pPoolSizes = (VkDescriptorPoolSize[1]) {
+                                                {
+                                                    .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                    .descriptorCount = self->descriptor_pool_maxsets
+                                                }
+                                            }
+                                        },
+                                        NULL,
+                                        &self->descriptor_pool);
+
+  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+                                    &(VkRenderPassCreateInfo) {
+                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+                                        .attachmentCount = 1,
+                                        .pAttachments = (VkAttachmentDescription[]) {
+                                           {
+                                              .format = gdk_vulkan_context_get_image_format (self->vulkan),
+                                              .samples = VK_SAMPLE_COUNT_1_BIT,
+                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+                                              .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+                                           }
+                                        },
+                                        .subpassCount = 1,
+                                        .pSubpasses = (VkSubpassDescription []) {
+                                           {
+                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                              .inputAttachmentCount = 0,
+                                              .colorAttachmentCount = 1,
+                                              .pColorAttachments = (VkAttachmentReference []) {
+                                                 {
+                                                    .attachment = 0,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pResolveAttachments = (VkAttachmentReference []) {
+                                                  {
+                                                     .attachment = VK_ATTACHMENT_UNUSED,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pDepthStencilAttachment = NULL,
+                                            }
+                                         },
+                                         .dependencyCount = 0
+                                      },
+                                      NULL,
+                                      &self->render_pass);
+
+  GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
+                                             &(VkDescriptorSetLayoutCreateInfo) {
+                                                 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+                                                 .bindingCount = 1,
+                                                 .pBindings = (VkDescriptorSetLayoutBinding[1]) {
+                                                     {
+                                                         .binding = 0,
+                                                         .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                         .descriptorCount = 1,
+                                                         .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
+                                                     }
+                                                 }
+                                             },
+                                             NULL,
+                                             &self->descriptor_set_layout);
+
+  for (guint i = 0; i < 3; i++)
+    {
+      VkDescriptorSetLayout layouts[3] = {
+        self->descriptor_set_layout,
+        self->descriptor_set_layout,
+        self->descriptor_set_layout
+      };
+
+      GSK_VK_CHECK (vkCreatePipelineLayout, device,
+                                            &(VkPipelineLayoutCreateInfo) {
+                                                .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+                                                .setLayoutCount = i,
+                                                .pSetLayouts = layouts,
+                                                .pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
+                                                .pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
+                                            },
+                                            NULL,
+                                            &self->pipeline_layout[i]);
+    }
+
+  GSK_VK_CHECK (vkCreateSampler, device,
+                                 &(VkSamplerCreateInfo) {
+                                     .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+                                     .magFilter = VK_FILTER_LINEAR,
+                                     .minFilter = VK_FILTER_LINEAR,
+                                     .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
+                                     .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
+                                     .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+                                     .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+                                     .unnormalizedCoordinates = VK_FALSE,
+                                     .maxAnisotropy = 1.0,
+                                 },
+                                 NULL,
+                                 &self->sampler);
+
+  GSK_VK_CHECK (vkCreateSampler, device,
+                                 &(VkSamplerCreateInfo) {
+                                     .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+                                     .magFilter = VK_FILTER_LINEAR,
+                                     .minFilter = VK_FILTER_LINEAR,
+                                     .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+                                     .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+                                     .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+                                     .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+                                     .unnormalizedCoordinates = VK_FALSE,
+                                     .maxAnisotropy = 1.0,
+                                 },
+                                 NULL,
+                                 &self->repeating_sampler);
+
+  self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
+
+#ifdef G_ENABLE_DEBUG
+  self->render_pass_counter = g_quark_from_static_string ("render-passes");
+  self->gpu_time_timer = g_quark_from_static_string ("gpu-time");
+#endif
+
+  return self;
+}
+
+typedef struct {
+  VkFramebuffer framebuffer;
+} HashFramebufferEntry;
+
+static void
+gsk_vulkan_render_remove_framebuffer_from_image (gpointer  data,
+                                                 GObject  *image)
+{
+  GskVulkanRender *self = data;
+  HashFramebufferEntry *fb;
+
+  fb = g_hash_table_lookup (self->framebuffers, image);
+  g_hash_table_remove (self->framebuffers, image);
+
+  vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
+                        fb->framebuffer,
+                        NULL);
+
+  g_slice_free (HashFramebufferEntry, fb);
+}
+
+VkFramebuffer
+gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
+                                   GskVulkanImage  *image)
+{
+  HashFramebufferEntry *fb;
+
+  fb = g_hash_table_lookup (self->framebuffers, image);
+  if (fb)
+    return fb->framebuffer;
+
+  fb = g_slice_new0 (HashFramebufferEntry);
+  GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
+                                     &(VkFramebufferCreateInfo) {
+                                         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+                                         .renderPass = self->render_pass,
+                                         .attachmentCount = 1,
+                                         .pAttachments = (VkImageView[1]) {
+                                             gsk_vulkan_image_get_image_view (image)
+                                         },
+                                         .width = gsk_vulkan_image_get_width (image),
+                                         .height = gsk_vulkan_image_get_height (image),
+                                         .layers = 1
+                                     },
+                                     NULL,
+                                     &fb->framebuffer);
+  g_hash_table_insert (self->framebuffers, image, fb);
+  g_object_weak_ref (G_OBJECT (image), gsk_vulkan_render_remove_framebuffer_from_image, self);
+
+  return fb->framebuffer;
+}
+
+void
+gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
+                                     GskVulkanImage  *image)
+{
+  self->cleanup_images = g_slist_prepend (self->cleanup_images, image);
+}
+
+void
+gsk_vulkan_render_add_render_pass (GskVulkanRender     *self,
+                                   GskVulkanRenderPass *pass)
+{
+  self->render_passes = g_list_prepend (self->render_passes, pass);
+
+#ifdef G_ENABLE_DEBUG
+  gsk_profiler_counter_inc (gsk_renderer_get_profiler (self->renderer), self->render_pass_counter);
+#endif
+}
+
+void
+gsk_vulkan_render_add_node (GskVulkanRender *self,
+                            GskRenderNode   *node)
+{
+  GskVulkanRenderPass *pass;
+  graphene_matrix_t mv;
+
+  graphene_matrix_init_scale (&mv, self->scale_factor, self->scale_factor, 1.0);
+
+  pass = gsk_vulkan_render_pass_new (self->vulkan,
+                                     self->target,
+                                     self->scale_factor,
+                                     &mv,
+                                     &self->viewport,
+                                     self->clip,
+                                     VK_NULL_HANDLE);
+
+  gsk_vulkan_render_add_render_pass (self, pass);
+
+  gsk_vulkan_render_pass_add (pass, self, node);
+}
+
+void
+gsk_vulkan_render_upload (GskVulkanRender *self)
+{
+  GList *l;
+
+  /* gsk_vulkan_render_pass_upload may call gsk_vulkan_render_add_node_for_texture,
+   * prepending new render passes to the list. Therefore, we walk the list from
+   * the end.
+   */
+  for (l = g_list_last (self->render_passes); l; l = l->prev)
+    {
+      GskVulkanRenderPass *pass = l->data;
+      gsk_vulkan_render_pass_upload (pass, self, self->uploader);
+    }
+
+  gsk_vulkan_uploader_upload (self->uploader);
+}
+
+GskVulkanPipeline *
+gsk_vulkan_render_get_pipeline (GskVulkanRender       *self,
+                                GskVulkanPipelineType  type)
+{
+  static const struct {
+    const char *name;
+    guint num_textures;
+    GskVulkanPipeline * (* create_func) (GdkVulkanContext *context, VkPipelineLayout layout, const char *name, VkRenderPass render_pass);
+  } pipeline_info[GSK_VULKAN_N_PIPELINES] = {
+    { "texture",                    1, gsk_vulkan_texture_pipeline_new },
+    { "texture-clip",               1, gsk_vulkan_texture_pipeline_new },
+    { "texture-clip-rounded",       1, gsk_vulkan_texture_pipeline_new },
+    { "color",                      0, gsk_vulkan_color_pipeline_new },
+    { "color-clip",                 0, gsk_vulkan_color_pipeline_new },
+    { "color-clip-rounded",         0, gsk_vulkan_color_pipeline_new },
+    { "linear",                     0, gsk_vulkan_linear_gradient_pipeline_new },
+    { "linear-clip",                0, gsk_vulkan_linear_gradient_pipeline_new },
+    { "linear-clip-rounded",        0, gsk_vulkan_linear_gradient_pipeline_new },
+    { "color-matrix",               1, gsk_vulkan_effect_pipeline_new },
+    { "color-matrix-clip",          1, gsk_vulkan_effect_pipeline_new },
+    { "color-matrix-clip-rounded",  1, gsk_vulkan_effect_pipeline_new },
+    { "border",                     0, gsk_vulkan_border_pipeline_new },
+    { "border-clip",                0, gsk_vulkan_border_pipeline_new },
+    { "border-clip-rounded",        0, gsk_vulkan_border_pipeline_new },
+    { "inset-shadow",               0, gsk_vulkan_box_shadow_pipeline_new },
+    { "inset-shadow-clip",          0, gsk_vulkan_box_shadow_pipeline_new },
+    { "inset-shadow-clip-rounded",  0, gsk_vulkan_box_shadow_pipeline_new },
+    { "outset-shadow",              0, gsk_vulkan_box_shadow_pipeline_new },
+    { "outset-shadow-clip",         0, gsk_vulkan_box_shadow_pipeline_new },
+    { "outset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
+    { "blur",                       1, gsk_vulkan_blur_pipeline_new },
+    { "blur-clip",                  1, gsk_vulkan_blur_pipeline_new },
+    { "blur-clip-rounded",          1, gsk_vulkan_blur_pipeline_new },
+    { "mask",                       1, gsk_vulkan_text_pipeline_new },
+    { "mask-clip",                  1, gsk_vulkan_text_pipeline_new },
+    { "mask-clip-rounded",          1, gsk_vulkan_text_pipeline_new },
+    { "texture",                    1, gsk_vulkan_color_text_pipeline_new },
+    { "texture-clip",               1, gsk_vulkan_color_text_pipeline_new },
+    { "texture-clip-rounded",       1, gsk_vulkan_color_text_pipeline_new },
+    { "crossfade",                  2, gsk_vulkan_cross_fade_pipeline_new },
+    { "crossfade-clip",             2, gsk_vulkan_cross_fade_pipeline_new },
+    { "crossfade-clip-rounded",     2, gsk_vulkan_cross_fade_pipeline_new },
+    { "blendmode",                  2, gsk_vulkan_blend_mode_pipeline_new },
+    { "blendmode-clip",             2, gsk_vulkan_blend_mode_pipeline_new },
+    { "blendmode-clip-rounded",     2, gsk_vulkan_blend_mode_pipeline_new },
+  };
+
+  g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
+
+  if (self->pipelines[type] == NULL)
+    self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
+                                                             self->pipeline_layout[pipeline_info[type].num_textures],
+                                                             pipeline_info[type].name,
+                                                             self->render_pass);
+
+  return self->pipelines[type];
+}
+
+VkDescriptorSet
+gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
+                                      gsize            id)
+{
+  g_assert (id < self->n_descriptor_sets);
+
+  return self->descriptor_sets[id];
+}
+
+typedef struct {
+  gsize index;
+  GskVulkanImage *image;
+  gboolean repeat;
+} HashDescriptorSetIndexEntry;
+
+static guint
+desc_set_index_hash (gconstpointer v)
+{
+  const HashDescriptorSetIndexEntry *e = v;
+
+  return GPOINTER_TO_UINT (e->image) + e->repeat;
+}
+
+static gboolean
+desc_set_index_equal (gconstpointer v1, gconstpointer v2)
+{
+  const HashDescriptorSetIndexEntry *e1 = v1;
+  const HashDescriptorSetIndexEntry *e2 = v2;
+
+  return e1->image == e2->image && e1->repeat == e2->repeat;
+}
+
+gsize
+gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
+                                          GskVulkanImage  *source,
+                                          gboolean         repeat)
+{
+  HashDescriptorSetIndexEntry lookup;
+  HashDescriptorSetIndexEntry *entry;
+
+  g_assert (source != NULL);
+
+  lookup.image = source;
+  lookup.repeat = repeat;
+
+  entry = g_hash_table_lookup (self->descriptor_set_indexes, &lookup);
+  if (entry)
+    return entry->index;
+
+  entry = g_new (HashDescriptorSetIndexEntry, 1);
+  entry->image = source;
+  entry->repeat = repeat;
+  entry->index = g_hash_table_size (self->descriptor_set_indexes);
+  g_hash_table_add (self->descriptor_set_indexes, entry);
+
+  return entry->index;
+}
+
+static void
+gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
+{
+  GHashTableIter iter;
+  gpointer key;
+  VkDevice device;
+  GList *l;
+  guint i, needed_sets;
+
+  device = gdk_vulkan_context_get_device (self->vulkan);
+
+  for (l = self->render_passes; l; l = l->next)
+    {
+      GskVulkanRenderPass *pass = l->data;
+      gsk_vulkan_render_pass_reserve_descriptor_sets (pass, self);
+    }
+  
+  needed_sets = g_hash_table_size (self->descriptor_set_indexes);
+  if (needed_sets > self->n_descriptor_sets)
+    {
+      if (needed_sets > self->descriptor_pool_maxsets)
+        {
+          guint added_sets = needed_sets - self->descriptor_pool_maxsets;
+          added_sets = added_sets + DESCRIPTOR_POOL_MAXSETS_INCREASE - 1;
+          added_sets -= added_sets % DESCRIPTOR_POOL_MAXSETS_INCREASE;
+
+          vkDestroyDescriptorPool (device,
+                                   self->descriptor_pool,
+                                   NULL);
+          self->descriptor_pool_maxsets += added_sets;
+          GSK_VK_CHECK (vkCreateDescriptorPool, device,
+                                                &(VkDescriptorPoolCreateInfo) {
+                                                    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+                                                    .maxSets = self->descriptor_pool_maxsets,
+                                                    .poolSizeCount = 1,
+                                                    .pPoolSizes = (VkDescriptorPoolSize[1]) {
+                                                        {
+                                                            .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                            .descriptorCount = self->descriptor_pool_maxsets
+                                                        }
+                                                    }
+                                                },
+                                                NULL,
+                                                &self->descriptor_pool);
+        }
+      else
+        {
+          GSK_VK_CHECK (vkResetDescriptorPool, device,
+                                               self->descriptor_pool,
+                                               0);
+        }
+
+      self->n_descriptor_sets = needed_sets;
+      self->descriptor_sets = g_renew (VkDescriptorSet, self->descriptor_sets, needed_sets);
+    }
+
+  VkDescriptorSetLayout *layouts = g_newa (VkDescriptorSetLayout, needed_sets);
+  for (i = 0; i < needed_sets; i++)
+    layouts[i] = self->descriptor_set_layout;
+
+  GSK_VK_CHECK (vkAllocateDescriptorSets, device,
+                                          &(VkDescriptorSetAllocateInfo) {
+                                              .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+                                              .descriptorPool = self->descriptor_pool,
+                                              .descriptorSetCount = needed_sets,
+                                              .pSetLayouts = layouts
+                                          },
+                                          self->descriptor_sets);
+
+  g_hash_table_iter_init (&iter, self->descriptor_set_indexes);
+  while (g_hash_table_iter_next (&iter, &key, NULL))
+    {
+      HashDescriptorSetIndexEntry *entry = key;
+      GskVulkanImage *image = entry->image;
+      gsize id = entry->index;
+      gboolean repeat = entry->repeat;
+
+      vkUpdateDescriptorSets (device,
+                              1,
+                              (VkWriteDescriptorSet[1]) {
+                                  {
+                                      .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+                                      .dstSet = self->descriptor_sets[id],
+                                      .dstBinding = 0,
+                                      .dstArrayElement = 0,
+                                      .descriptorCount = 1,
+                                      .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                      .pImageInfo = &(VkDescriptorImageInfo) {
+                                          .sampler = repeat ? self->repeating_sampler : self->sampler,
+                                          .imageView = gsk_vulkan_image_get_image_view (image),
+                                          .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+                                      }
+                                  }
+                              },
+                              0, NULL);
+    }
+}
+
+void
+gsk_vulkan_render_draw (GskVulkanRender *self)
+{
+  GList *l;
+
+#ifdef G_ENABLE_DEBUG
+  if (GSK_RENDER_MODE_CHECK (SYNC))
+    gsk_profiler_timer_begin (gsk_renderer_get_profiler (self->renderer), self->gpu_time_timer);
+#endif
+
+  gsk_vulkan_render_prepare_descriptor_sets (self);
+
+  for (l = self->render_passes; l; l = l->next)
+    {
+      GskVulkanRenderPass *pass = l->data;
+      VkCommandBuffer command_buffer;
+      gsize wait_semaphore_count;
+      gsize signal_semaphore_count;
+      VkSemaphore *wait_semaphores;
+      VkSemaphore *signal_semaphores;
+
+      wait_semaphore_count = gsk_vulkan_render_pass_get_wait_semaphores (pass, &wait_semaphores);
+      signal_semaphore_count = gsk_vulkan_render_pass_get_signal_semaphores (pass, &signal_semaphores);
+
+      command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+
+      gsk_vulkan_render_pass_draw (pass, self, 3, self->pipeline_layout, command_buffer);
+
+      gsk_vulkan_command_pool_submit_buffer (self->command_pool,
+                                             command_buffer,
+                                             wait_semaphore_count,
+                                             wait_semaphores,
+                                             signal_semaphore_count,
+                                             signal_semaphores,
+                                             l->next != NULL ? VK_NULL_HANDLE : self->fence);
+    }
+
+  if (GSK_RENDER_MODE_CHECK (SYNC))
+    {
+      GskProfiler *profiler;
+      gint64 gpu_time;
+
+      GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan),
+                                     1,
+                                     &self->fence,
+                                     VK_TRUE,
+                                     INT64_MAX);
+
+      profiler = gsk_renderer_get_profiler (self->renderer);
+      gpu_time = gsk_profiler_timer_end (profiler, self->gpu_time_timer);
+      gsk_profiler_timer_set (profiler, self->gpu_time_timer, gpu_time);
+    }
+}
+
+GdkTexture *
+gsk_vulkan_render_download_target (GskVulkanRender *self)
+{
+  gsk_vulkan_uploader_reset (self->uploader);
+
+  return gsk_vulkan_image_download (self->target, self->uploader);
+}
+
+static void
+gsk_vulkan_render_cleanup (GskVulkanRender *self)
+{
+  VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
+
+  /* XXX: Wait for fence here or just in reset()? */
+  GSK_VK_CHECK (vkWaitForFences, device,
+                                 1,
+                                 &self->fence,
+                                 VK_TRUE,
+                                 INT64_MAX);
+
+  GSK_VK_CHECK (vkResetFences, device,
+                               1,
+                               &self->fence);
+
+  gsk_vulkan_uploader_reset (self->uploader);
+
+  gsk_vulkan_command_pool_reset (self->command_pool);
+
+  g_hash_table_remove_all (self->descriptor_set_indexes);
+  GSK_VK_CHECK (vkResetDescriptorPool, device,
+                                       self->descriptor_pool,
+                                       0);
+
+  g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
+  self->render_passes = NULL;
+  g_slist_free_full (self->cleanup_images, g_object_unref);
+  self->cleanup_images = NULL;
+
+  g_clear_pointer (&self->clip, cairo_region_destroy);
+  g_clear_object (&self->target);
+}
+
+void
+gsk_vulkan_render_free (GskVulkanRender *self)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+  VkDevice device;
+  guint i;
+  
+  gsk_vulkan_render_cleanup (self);
+
+  device = gdk_vulkan_context_get_device (self->vulkan);
+
+  g_hash_table_iter_init (&iter, self->framebuffers);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      HashFramebufferEntry *fb = value;
+
+      vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
+                            fb->framebuffer,
+                            NULL);
+      g_slice_free (HashFramebufferEntry, fb);
+      g_object_weak_unref (G_OBJECT (key), gsk_vulkan_render_remove_framebuffer_from_image, self);
+      g_hash_table_iter_remove (&iter);
+    }
+  g_hash_table_unref (self->framebuffers);
+
+  for (i = 0; i < GSK_VULKAN_N_PIPELINES; i++)
+    g_clear_object (&self->pipelines[i]);
+
+  g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
+
+  for (i = 0; i < 3; i++)
+    vkDestroyPipelineLayout (device,
+                             self->pipeline_layout[i],
+                             NULL);
+
+  vkDestroyRenderPass (device,
+                       self->render_pass,
+                       NULL);
+
+  vkDestroyDescriptorPool (device,
+                           self->descriptor_pool,
+                           NULL);
+  g_free (self->descriptor_sets);
+  g_hash_table_unref (self->descriptor_set_indexes);
+
+  vkDestroyDescriptorSetLayout (device,
+                                self->descriptor_set_layout,
+                                NULL);
+
+  vkDestroyFence (device,
+                  self->fence,
+                  NULL);
+
+  vkDestroySampler (device,
+                    self->sampler,
+                    NULL);
+
+  vkDestroySampler (device,
+                    self->repeating_sampler,
+                    NULL);
+
+  gsk_vulkan_command_pool_free (self->command_pool);
+
+  g_slice_free (GskVulkanRender, self);
+}
+
+gboolean
+gsk_vulkan_render_is_busy (GskVulkanRender *self)
+{
+  return vkGetFenceStatus (gdk_vulkan_context_get_device (self->vulkan), self->fence) != VK_SUCCESS;
+}
+
+void
+gsk_vulkan_render_reset (GskVulkanRender       *self,
+                         GskVulkanImage        *target,
+                         const graphene_rect_t *rect)
+{
+  gsk_vulkan_render_cleanup (self);
+
+  gsk_vulkan_render_setup (self, target, rect);
+}
+
+GskRenderer *
+gsk_vulkan_render_get_renderer (GskVulkanRender *self)
+{
+  return self->renderer;
+}
diff --git a/gsk/vulkan/gskvulkanrenderer.c b/gsk/vulkan/gskvulkanrenderer.c
new file mode 100644 (file)
index 0000000..82c25ec
--- /dev/null
@@ -0,0 +1,375 @@
+#include "config.h"
+
+#include "gskvulkanrendererprivate.h"
+
+#include "gskdebugprivate.h"
+#include "gskprivate.h"
+#include "gskrendererprivate.h"
+#include "gskrendernodeprivate.h"
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderprivate.h"
+#include "gskvulkanglyphcacheprivate.h"
+
+#include "gdk/gdktextureprivate.h"
+
+#include <graphene.h>
+
+typedef struct _GskVulkanTextureData GskVulkanTextureData;
+
+struct _GskVulkanTextureData {
+  GdkTexture *texture;
+  GskVulkanImage *image;
+  GskVulkanRenderer *renderer;
+};
+
+#ifdef G_ENABLE_DEBUG
+typedef struct {
+  GQuark frames;
+  GQuark render_passes;
+  GQuark fallback_pixels;
+  GQuark texture_pixels;
+} ProfileCounters;
+
+typedef struct {
+  GQuark cpu_time;
+  GQuark gpu_time;
+} ProfileTimers;
+#endif
+
+struct _GskVulkanRenderer
+{
+  GskRenderer parent_instance;
+
+  GdkVulkanContext *vulkan;
+
+  guint n_targets;
+  GskVulkanImage **targets;
+
+  GskVulkanRender *render;
+
+  GSList *textures;
+
+  GskVulkanGlyphCache *glyph_cache;
+
+#ifdef G_ENABLE_DEBUG
+  ProfileCounters profile_counters;
+  ProfileTimers profile_timers;
+#endif
+};
+
+struct _GskVulkanRendererClass
+{
+  GskRendererClass parent_class;
+};
+
+G_DEFINE_TYPE (GskVulkanRenderer, gsk_vulkan_renderer, GSK_TYPE_RENDERER)
+
+static void
+gsk_vulkan_renderer_free_targets (GskVulkanRenderer *self)
+{
+  guint i;
+
+  for (i = 0; i < self->n_targets; i++)
+    {
+      g_object_unref (self->targets[i]);
+    }
+
+  g_clear_pointer (&self->targets, g_free);
+  self->n_targets = 0;
+}
+
+static void
+gsk_vulkan_renderer_update_images_cb (GdkVulkanContext  *context,
+                                      GskVulkanRenderer *self)
+{
+  GdkWindow *window;
+  gint scale_factor;
+  gsize width, height;
+  guint i;
+
+  gsk_vulkan_renderer_free_targets (self);
+
+  self->n_targets = gdk_vulkan_context_get_n_images (context);
+  self->targets = g_new (GskVulkanImage *, self->n_targets);
+
+  window = gsk_renderer_get_window (GSK_RENDERER (self));
+  scale_factor = gdk_window_get_scale_factor (window);
+  width = gdk_window_get_width (window) * scale_factor;
+  height = gdk_window_get_height (window) * scale_factor;
+
+  for (i = 0; i < self->n_targets; i++)
+    {
+      self->targets[i] = gsk_vulkan_image_new_for_swapchain (self->vulkan,
+                                                             gdk_vulkan_context_get_image (context, i),
+                                                             gdk_vulkan_context_get_image_format (self->vulkan),
+                                                             width, height);
+    }
+}
+
+static gboolean
+gsk_vulkan_renderer_realize (GskRenderer  *renderer,
+                             GdkWindow    *window,
+                             GError      **error)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+
+  self->vulkan = gdk_window_create_vulkan_context (window, error);
+  if (self->vulkan == NULL)
+    return FALSE;
+
+  g_signal_connect (self->vulkan,
+                    "images-updated",
+                    G_CALLBACK (gsk_vulkan_renderer_update_images_cb),
+                    self);
+  gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
+
+  self->render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+  self->glyph_cache = gsk_vulkan_glyph_cache_new (self->vulkan);
+
+  return TRUE;
+}
+
+static void
+gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GSList *l;
+
+  g_clear_object (&self->glyph_cache);
+
+  for (l = self->textures; l; l = l->next)
+    {
+      GskVulkanTextureData *data = l->data;
+
+      data->renderer = NULL;
+      gdk_texture_clear_render_data (data->texture);
+    }
+  g_clear_pointer (&self->textures, (GDestroyNotify) g_slist_free);
+
+  g_clear_pointer (&self->render, gsk_vulkan_render_free);
+
+  gsk_vulkan_renderer_free_targets (self);
+  g_signal_handlers_disconnect_by_func(self->vulkan,
+                                       gsk_vulkan_renderer_update_images_cb,
+                                       self);
+
+  g_clear_object (&self->vulkan);
+}
+
+static GdkTexture *
+gsk_vulkan_renderer_render_texture (GskRenderer           *renderer,
+                                    GskRenderNode         *root,
+                                    const graphene_rect_t *viewport)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GskVulkanRender *render;
+  GskVulkanImage *image;
+  GdkTexture *texture;
+#ifdef G_ENABLE_DEBUG
+  GskProfiler *profiler;
+  gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+  profiler = gsk_renderer_get_profiler (renderer);
+  gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
+  gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
+  gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
+  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+  render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+  image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
+                                                ceil (viewport->size.width),
+                                                ceil (viewport->size.height));
+
+  gsk_vulkan_render_reset (render, image, viewport);
+
+  gsk_vulkan_render_add_node (render, root);
+
+  gsk_vulkan_render_upload (render);
+
+  gsk_vulkan_render_draw (render);
+
+  texture = gsk_vulkan_render_download_target (render);
+
+  g_object_unref (image);
+  gsk_vulkan_render_free (render);
+
+#ifdef G_ENABLE_DEBUG
+  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+  gsk_profiler_push_samples (profiler);
+#endif
+
+  return texture;
+}
+
+static void
+gsk_vulkan_renderer_render (GskRenderer   *renderer,
+                            GskRenderNode *root)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GskVulkanRender *render;
+#ifdef G_ENABLE_DEBUG
+  GskProfiler *profiler;
+  gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+  profiler = gsk_renderer_get_profiler (renderer);
+  gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
+  gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
+  gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
+  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+  render = self->render;
+
+  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
+
+  gsk_vulkan_render_add_node (render, root);
+
+  gsk_vulkan_render_upload (render);
+
+  gsk_vulkan_render_draw (render);
+
+#ifdef G_ENABLE_DEBUG
+  gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
+
+  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+  gsk_profiler_push_samples (profiler);
+#endif
+}
+
+static GdkDrawingContext *
+gsk_vulkan_renderer_begin_draw_frame (GskRenderer          *renderer,
+                                      const cairo_region_t *region)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GdkDrawingContext *result;
+
+  result = gdk_window_begin_draw_frame (gsk_renderer_get_window (renderer),
+                                        GDK_DRAW_CONTEXT (self->vulkan),
+                                        region);
+
+  return result;
+}
+
+static void
+gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
+{
+  GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
+
+  renderer_class->realize = gsk_vulkan_renderer_realize;
+  renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
+  renderer_class->render = gsk_vulkan_renderer_render;
+  renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
+  renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
+}
+
+static void
+gsk_vulkan_renderer_init (GskVulkanRenderer *self)
+{
+#ifdef G_ENABLE_DEBUG
+  GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
+#endif
+
+  gsk_ensure_resources ();
+
+#ifdef G_ENABLE_DEBUG
+  self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
+  self->profile_counters.render_passes = gsk_profiler_add_counter (profiler, "render-passes", "Render passes", FALSE);
+  self->profile_counters.fallback_pixels = gsk_profiler_add_counter (profiler, "fallback-pixels", "Fallback pixels", TRUE);
+  self->profile_counters.texture_pixels = gsk_profiler_add_counter (profiler, "texture-pixels", "Texture pixels", TRUE);
+
+  self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
+  if (GSK_RENDER_MODE_CHECK (SYNC))
+    self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
+#endif
+}
+
+static void
+gsk_vulkan_renderer_clear_texture (gpointer p)
+{
+  GskVulkanTextureData *data = p;
+
+  if (data->renderer != NULL)
+    data->renderer->textures = g_slist_remove (data->renderer->textures, data);
+
+  g_object_unref (data->image);
+
+  g_slice_free (GskVulkanTextureData, data);
+}
+
+GskVulkanImage *
+gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
+                                       GdkTexture        *texture,
+                                       GskVulkanUploader *uploader)
+{
+  GskVulkanTextureData *data;
+  cairo_surface_t *surface;
+  GskVulkanImage *image;
+
+  data = gdk_texture_get_render_data (texture, self);
+  if (data)
+    return g_object_ref (data->image);
+
+  surface = gdk_texture_download_surface (texture);
+  image = gsk_vulkan_image_new_from_data (uploader,
+                                          cairo_image_surface_get_data (surface),
+                                          cairo_image_surface_get_width (surface),
+                                          cairo_image_surface_get_height (surface),
+                                          cairo_image_surface_get_stride (surface));
+  cairo_surface_destroy (surface);
+
+  data = g_slice_new0 (GskVulkanTextureData);
+  data->image = image;
+  data->texture = texture;
+  data->renderer = self;
+
+  if (gdk_texture_set_render_data (texture, self, data, gsk_vulkan_renderer_clear_texture))
+    {
+      g_object_ref (data->image);
+      self->textures = g_slist_prepend (self->textures, data);
+    }
+  else
+    {
+      g_slice_free (GskVulkanTextureData, data);
+    }
+
+  return image;
+}
+
+guint
+gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
+                                 PangoFont         *font,
+                                 PangoGlyph         glyph,
+                                 float              scale)
+{
+  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
+}
+
+GskVulkanImage *
+gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer  *self,
+                                     GskVulkanUploader  *uploader,
+                                     guint               index)
+{
+  return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
+}
+
+GskVulkanCachedGlyph *
+gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
+                                      PangoFont         *font,
+                                      PangoGlyph         glyph,
+                                      float              scale)
+{
+  return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
+}
diff --git a/gsk/vulkan/gskvulkanrendererprivate.h b/gsk/vulkan/gskvulkanrendererprivate.h
new file mode 100644 (file)
index 0000000..1e7d78a
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __GSK_VULKAN_RENDERER_PRIVATE_H__
+#define __GSK_VULKAN_RENDERER_PRIVATE_H__
+
+#include <vulkan/vulkan.h>
+#include <gsk/gskrenderer.h>
+
+#include "gskvulkanimageprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
+
+#define GSK_VULKAN_RENDERER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
+#define GSK_IS_VULKAN_RENDERER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
+#define GSK_VULKAN_RENDERER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
+#define GSK_IS_VULKAN_RENDERER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
+#define GSK_VULKAN_RENDERER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
+
+typedef struct _GskVulkanRenderer                GskVulkanRenderer;
+typedef struct _GskVulkanRendererClass           GskVulkanRendererClass;
+
+GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
+
+GskVulkanImage *        gsk_vulkan_renderer_ref_texture_image           (GskVulkanRenderer      *self,
+                                                                         GdkTexture             *texture,
+                                                                         GskVulkanUploader      *uploader);
+
+typedef struct
+{
+  guint texture_index;
+
+  float tx;
+  float ty;
+  float tw;
+  float th;
+
+  int draw_x;
+  int draw_y;
+  int draw_width;
+  int draw_height;
+
+  guint64 timestamp;
+} GskVulkanCachedGlyph;
+
+guint                  gsk_vulkan_renderer_cache_glyph      (GskVulkanRenderer *renderer,
+                                                             PangoFont         *font,
+                                                             PangoGlyph         glyph,
+                                                             float              scale);
+
+GskVulkanImage *       gsk_vulkan_renderer_ref_glyph_image  (GskVulkanRenderer *self,
+                                                             GskVulkanUploader *uploader,
+                                                             guint              index);
+
+GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
+                                                             PangoFont         *font,
+                                                             PangoGlyph         glyph,
+                                                             float              scale);
+
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c
new file mode 100644 (file)
index 0000000..83fff2d
--- /dev/null
@@ -0,0 +1,1942 @@
+#include "config.h"
+
+#include "gskvulkanrenderpassprivate.h"
+
+#include "gskdebugprivate.h"
+#include "gskprofilerprivate.h"
+#include "gskrendernodeprivate.h"
+#include "gskrenderer.h"
+#include "gskrendererprivate.h"
+#include "gskroundedrectprivate.h"
+#include "gskvulkanblendmodepipelineprivate.h"
+#include "gskvulkanblurpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
+#include "gskvulkanboxshadowpipelineprivate.h"
+#include "gskvulkanclipprivate.h"
+#include "gskvulkancolorpipelineprivate.h"
+#include "gskvulkancolortextpipelineprivate.h"
+#include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkaneffectpipelineprivate.h"
+#include "gskvulkanlineargradientpipelineprivate.h"
+#include "gskvulkantextpipelineprivate.h"
+#include "gskvulkantexturepipelineprivate.h"
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpushconstantsprivate.h"
+#include "gskvulkanrendererprivate.h"
+#include "gskprivate.h"
+
+#include <cairo-ft.h>
+
+#define ORTHO_NEAR_PLANE        -10000
+#define ORTHO_FAR_PLANE          10000
+
+typedef union _GskVulkanOp GskVulkanOp;
+typedef struct _GskVulkanOpRender GskVulkanOpRender;
+typedef struct _GskVulkanOpText GskVulkanOpText;
+typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
+
+typedef enum {
+  /* GskVulkanOpRender */
+  GSK_VULKAN_OP_FALLBACK,
+  GSK_VULKAN_OP_FALLBACK_CLIP,
+  GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
+  GSK_VULKAN_OP_SURFACE,
+  GSK_VULKAN_OP_TEXTURE,
+  GSK_VULKAN_OP_COLOR,
+  GSK_VULKAN_OP_LINEAR_GRADIENT,
+  GSK_VULKAN_OP_OPACITY,
+  GSK_VULKAN_OP_BLUR,
+  GSK_VULKAN_OP_COLOR_MATRIX,
+  GSK_VULKAN_OP_BORDER,
+  GSK_VULKAN_OP_INSET_SHADOW,
+  GSK_VULKAN_OP_OUTSET_SHADOW,
+  GSK_VULKAN_OP_REPEAT,
+  GSK_VULKAN_OP_CROSS_FADE,
+  GSK_VULKAN_OP_BLEND_MODE,
+  /* GskVulkanOpText */
+  GSK_VULKAN_OP_TEXT,
+  GSK_VULKAN_OP_COLOR_TEXT,
+  /* GskVulkanOpPushConstants */
+  GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
+} GskVulkanOpType;
+
+/* render ops with 0, 1 or 2 sources */
+struct _GskVulkanOpRender
+{
+  GskVulkanOpType      type;
+  GskRenderNode       *node; /* node that's the source of this op */
+  GskVulkanPipeline   *pipeline; /* pipeline to use */
+  GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
+  GskVulkanImage      *source; /* source image to render */
+  GskVulkanImage      *source2; /* second source image to render (if relevant) */
+  gsize                vertex_offset; /* offset into vertex buffer */
+  gsize                vertex_count; /* number of vertices */
+  gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
+  gsize                descriptor_set_index2; /* descriptor index for the second source (if relevant) */
+  graphene_rect_t      source_rect; /* area that source maps to */
+  graphene_rect_t      source2_rect; /* area that source2 maps to */
+};
+
+struct _GskVulkanOpText
+{
+  GskVulkanOpType      type;
+  GskRenderNode       *node; /* node that's the source of this op */
+  GskVulkanPipeline   *pipeline; /* pipeline to use */
+  GskRoundedRect       clip; /* clip rect (or random memory if not relevant) */
+  GskVulkanImage      *source; /* source image to render */
+  gsize                vertex_offset; /* offset into vertex buffer */
+  gsize                vertex_count; /* number of vertices */
+  gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
+  guint                texture_index; /* index of the texture in the glyph cache */
+  guint                start_glyph; /* the first glyph in nodes glyphstring that we render */
+  guint                num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
+  float                scale;
+};
+
+struct _GskVulkanOpPushConstants
+{
+  GskVulkanOpType         type;
+  GskRenderNode          *node; /* node that's the source of this op */
+  GskVulkanPushConstants  constants; /* new constants to push */
+};
+
+union _GskVulkanOp
+{
+  GskVulkanOpType          type;
+  GskVulkanOpRender        render;
+  GskVulkanOpText          text;
+  GskVulkanOpPushConstants constants;
+};
+
+struct _GskVulkanRenderPass
+{
+  GdkVulkanContext *vulkan;
+
+  GArray *render_ops;
+
+  GskVulkanImage *target;
+  int scale_factor;
+  graphene_rect_t viewport;
+  cairo_region_t *clip;
+  graphene_matrix_t mv;
+  graphene_matrix_t p;
+
+  VkRenderPass render_pass;
+  VkSemaphore signal_semaphore;
+  GArray *wait_semaphores;
+  GskVulkanBuffer *vertex_data;
+
+  GQuark fallback_pixels;
+  GQuark texture_pixels;
+};
+
+GskVulkanRenderPass *
+gsk_vulkan_render_pass_new (GdkVulkanContext  *context,
+                            GskVulkanImage    *target,
+                            int                scale_factor,
+                            graphene_matrix_t *mv,
+                            graphene_rect_t   *viewport,
+                            cairo_region_t    *clip,
+                            VkSemaphore        signal_semaphore)
+{
+  GskVulkanRenderPass *self;
+  VkImageLayout final_layout;
+
+  self = g_slice_new0 (GskVulkanRenderPass);
+  self->vulkan = g_object_ref (context);
+  self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
+
+  self->target = g_object_ref (target);
+  self->scale_factor = scale_factor;
+  self->clip = cairo_region_copy (clip);
+  self->viewport = *viewport;
+
+  self->mv = *mv;
+  graphene_matrix_init_ortho (&self->p,
+                              viewport->origin.x, viewport->origin.x + viewport->size.width,
+                              viewport->origin.y, viewport->origin.y + viewport->size.height,
+                              ORTHO_NEAR_PLANE,
+                              ORTHO_FAR_PLANE);
+
+  if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
+    final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+  else
+    final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+  GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+                                    &(VkRenderPassCreateInfo) {
+                                        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+                                        .attachmentCount = 1,
+                                        .pAttachments = (VkAttachmentDescription[]) {
+                                           {
+                                              .format = gdk_vulkan_context_get_image_format (self->vulkan),
+                                              .samples = VK_SAMPLE_COUNT_1_BIT,
+                                              .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+                                              .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+                                              .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+                                              .finalLayout = final_layout
+                                           }
+                                        },
+                                        .subpassCount = 1,
+                                        .pSubpasses = (VkSubpassDescription []) {
+                                           {
+                                              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                              .inputAttachmentCount = 0,
+                                              .colorAttachmentCount = 1,
+                                              .pColorAttachments = (VkAttachmentReference []) {
+                                                 {
+                                                    .attachment = 0,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pResolveAttachments = (VkAttachmentReference []) {
+                                                  {
+                                                     .attachment = VK_ATTACHMENT_UNUSED,
+                                                     .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+                                                  }
+                                               },
+                                               .pDepthStencilAttachment = NULL,
+                                            }
+                                         },
+                                         .dependencyCount = 0
+                                      },
+                                      NULL,
+                                      &self->render_pass);
+
+  self->signal_semaphore = signal_semaphore;
+  self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
+  self->vertex_data = NULL;
+
+#ifdef G_ENABLE_DEBUG
+  self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
+  self->texture_pixels = g_quark_from_static_string ("texture-pixels");
+#endif
+
+  return self;
+}
+
+void
+gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
+{
+  g_array_unref (self->render_ops);
+  g_object_unref (self->vulkan);
+  g_object_unref (self->target);
+  cairo_region_destroy (self->clip);
+  vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
+                       self->render_pass,
+                       NULL);
+  if (self->vertex_data)
+    gsk_vulkan_buffer_free (self->vertex_data);
+  if (self->signal_semaphore != VK_NULL_HANDLE)
+    vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
+                        self->signal_semaphore,
+                        NULL);
+  g_array_unref (self->wait_semaphores);
+
+
+  g_slice_free (GskVulkanRenderPass, self);
+}
+
+static gboolean
+font_has_color_glyphs (const PangoFont *font)
+{
+  cairo_scaled_font_t *scaled_font;
+  gboolean has_color = FALSE;
+
+  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
+  if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
+    {
+      FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+      has_color = (FT_HAS_COLOR (ft_face) != 0);
+      cairo_ft_scaled_font_unlock_face (scaled_font);
+    }
+
+  return has_color;
+}
+
+#define FALLBACK(...) G_STMT_START { \
+  GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
+  goto fallback; \
+}G_STMT_END
+
+static void
+gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
+                                 GskVulkanRender               *render,
+                                 const GskVulkanPushConstants  *constants,
+                                 GskRenderNode                 *node)
+{
+  GskVulkanOp op = {
+    .type = GSK_VULKAN_OP_FALLBACK,
+    .render.node = node
+  };
+  GskVulkanPipelineType pipeline_type;
+
+  switch (gsk_render_node_get_node_type (node))
+    {
+    case GSK_NOT_A_RENDER_NODE:
+      g_assert_not_reached ();
+      return;
+    case GSK_SHADOW_NODE:
+    default:
+      FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
+
+    case GSK_REPEAT_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+      else
+        FALLBACK ("Repeat nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_REPEAT;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_BLEND_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
+      else
+        FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_BLEND_MODE;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+       return;
+
+    case GSK_CROSS_FADE_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
+      else
+        FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_CROSS_FADE;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_INSET_SHADOW_NODE:
+      if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
+        FALLBACK ("Blur support not implemented for inset shadows\n");
+      else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
+      else
+        FALLBACK ("Inset shadow nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_INSET_SHADOW;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_OUTSET_SHADOW_NODE:
+      if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
+        FALLBACK ("Blur support not implemented for outset shadows\n");
+      else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
+      else
+        FALLBACK ("Outset shadow nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_CAIRO_NODE:
+      if (gsk_cairo_node_peek_surface (node) == NULL)
+        return;
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+      else
+        FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_SURFACE;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_TEXT_NODE:
+      {
+        const PangoFont *font = gsk_text_node_peek_font (node);
+        const PangoGlyphInfo *glyphs = gsk_text_node_peek_glyphs (node);
+        guint num_glyphs = gsk_text_node_get_num_glyphs (node);
+        int i;
+        guint count;
+        guint texture_index;
+        GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
+
+        if (font_has_color_glyphs (font))
+          {
+            if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
+            else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
+            else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+              pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
+            else
+              FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+            op.type = GSK_VULKAN_OP_COLOR_TEXT;
+          }
+        else
+          {
+            if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+              pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
+            else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+              pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
+            else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+              pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
+            else
+              FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+            op.type = GSK_VULKAN_OP_TEXT;
+          }
+        op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+
+        op.text.start_glyph = 0;
+        op.text.texture_index = G_MAXUINT;
+        op.text.scale = self->scale_factor;
+
+        for (i = 0, count = 0; i < num_glyphs; i++)
+          {
+            const PangoGlyphInfo *gi = &glyphs[i];
+
+            texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale);
+            if (op.text.texture_index == G_MAXUINT)
+              op.text.texture_index = texture_index;
+            if (texture_index != op.text.texture_index)
+              {
+                op.text.num_glyphs = count;
+
+                g_array_append_val (self->render_ops, op);
+
+                count = 1;
+                op.text.start_glyph = i;
+                op.text.texture_index = texture_index;
+              }
+            else
+              count++;
+          }
+
+        if (op.text.texture_index != G_MAXUINT && count != 0)
+          {
+            op.text.num_glyphs = count;
+            g_array_append_val (self->render_ops, op);
+          }
+
+        return;
+      }
+
+    case GSK_TEXTURE_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+      else
+        FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_TEXTURE;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_COLOR_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
+      else
+        FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_COLOR;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_LINEAR_GRADIENT_NODE:
+    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+      if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
+        FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u\n",
+                  gsk_linear_gradient_node_get_n_color_stops (node),
+                  GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
+      else
+        FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_OPACITY_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
+      else
+        FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_OPACITY;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_BLUR_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
+      else
+        FALLBACK ("Blur nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_BLUR;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_COLOR_MATRIX_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
+      else
+        FALLBACK ("Color matrix nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_COLOR_MATRIX;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_BORDER_NODE:
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+        pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
+      else
+        FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
+      op.type = GSK_VULKAN_OP_BORDER;
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+      g_array_append_val (self->render_ops, op);
+      return;
+
+    case GSK_CONTAINER_NODE:
+      {
+        guint i;
+
+        for (i = 0; i < gsk_container_node_get_n_children (node); i++)
+          {
+            gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
+          }
+      }
+      return;
+
+    case GSK_TRANSFORM_NODE:
+      {
+        graphene_matrix_t transform, mv;
+        GskRenderNode *child;
+
+#if 0
+       if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
+          FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
+#endif
+
+        graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
+        graphene_matrix_init_from_matrix (&mv, &self->mv);
+        graphene_matrix_multiply (&transform, &mv, &self->mv);
+        child = gsk_transform_node_get_child (node);
+        if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
+          FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
+        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+        g_array_append_val (self->render_ops, op);
+
+        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
+        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+        graphene_matrix_init_from_matrix (&self->mv, &mv);
+        g_array_append_val (self->render_ops, op);
+      }
+      return;
+
+    case GSK_CLIP_NODE:
+      {
+        if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
+          FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
+        if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
+          return;
+
+        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+        g_array_append_val (self->render_ops, op);
+
+        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
+
+        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+        g_array_append_val (self->render_ops, op);
+      }
+      return;
+
+    case GSK_ROUNDED_CLIP_NODE:
+      {
+        if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
+                                                          constants,
+                                                          gsk_rounded_clip_node_peek_clip (node)))
+          FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
+        if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
+          return;
+
+        op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+        g_array_append_val (self->render_ops, op);
+
+        gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
+
+        gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+        g_array_append_val (self->render_ops, op);
+      }
+      return;
+    }
+
+  g_assert_not_reached ();
+  return;
+
+fallback:
+  switch (constants->clip.type)
+    {
+      case GSK_VULKAN_CLIP_NONE:
+        op.type = GSK_VULKAN_OP_FALLBACK;
+        break;
+      case GSK_VULKAN_CLIP_RECT:
+        op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
+        gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
+        break;
+      case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+      case GSK_VULKAN_CLIP_ROUNDED:
+        op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
+        gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
+        break;
+      case GSK_VULKAN_CLIP_ALL_CLIPPED:
+      default:
+        g_assert_not_reached ();
+        return;
+    }
+  op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
+  g_array_append_val (self->render_ops, op);
+}
+#undef FALLBACK
+
+void
+gsk_vulkan_render_pass_add (GskVulkanRenderPass     *self,
+                            GskVulkanRender         *render,
+                            GskRenderNode           *node)
+{
+  GskVulkanOp op = { 0, };
+  graphene_matrix_t mvp;
+
+  graphene_matrix_multiply (&self->mv, &self->p, &mvp);
+  op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+  gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
+  g_array_append_val (self->render_ops, op);
+
+  gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
+}
+
+static GskVulkanImage *
+gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass   *self,
+                                            GskVulkanRender       *render,
+                                            GskVulkanUploader     *uploader,
+                                            GskRenderNode         *node,
+                                            const graphene_rect_t *bounds,
+                                            GskVulkanClip         *current_clip,
+                                            graphene_rect_t       *tex_rect)
+{
+  GskVulkanImage *result;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  switch ((guint) gsk_render_node_get_node_type (node))
+    {
+    case GSK_TEXTURE_NODE:
+      if (graphene_rect_equal (bounds, &node->bounds))
+        {
+          result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+                                                          gsk_texture_node_get_texture (node),
+                                                          uploader);
+          gsk_vulkan_render_add_cleanup_image (render, result);
+          *tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+          return result;
+        }
+      break;
+
+    case GSK_CAIRO_NODE:
+      if (graphene_rect_equal (bounds, &node->bounds))
+        {
+          surface = cairo_surface_reference ((cairo_surface_t *)gsk_cairo_node_peek_surface (node));
+          goto got_surface;
+        }
+      break;
+
+    default:
+      {
+        VkSemaphore semaphore;
+        graphene_rect_t view;
+        cairo_region_t *clip;
+        GskVulkanRenderPass *pass;
+        graphene_rect_t clipped;
+
+        if (current_clip)
+          graphene_rect_intersection (&current_clip->rect.bounds, bounds, &clipped);
+        else
+          clipped = *bounds;
+
+        if (clipped.size.width == 0 || clipped.size.height == 0)
+          return NULL;
+
+        graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
+        view.origin.x = floor (view.origin.x);
+        view.origin.y = floor (view.origin.y);
+        view.size.width = ceil (view.size.width);
+        view.size.height = ceil (view.size.height);
+
+        result = gsk_vulkan_image_new_for_texture (self->vulkan,
+                                                   view.size.width,
+                                                   view.size.height);
+
+#ifdef G_ENABLE_DEBUG
+        {
+          GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+          gsk_profiler_counter_add (profiler,
+                                    self->texture_pixels,
+                                    view.size.width * view.size.height);
+        }
+#endif
+
+        vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
+                           &(VkSemaphoreCreateInfo) {
+                             VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+                             NULL,
+                             0
+                           },
+                           NULL,
+                           &semaphore);
+
+        g_array_append_val (self->wait_semaphores, semaphore);
+
+        clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+                                                0, 0,
+                                                gsk_vulkan_image_get_width (result),
+                                                gsk_vulkan_image_get_height (result)
+                                              });
+
+        pass = gsk_vulkan_render_pass_new (self->vulkan,
+                                           result,
+                                           self->scale_factor,
+                                           &self->mv,
+                                           &view,
+                                           clip,
+                                           semaphore);
+
+        cairo_region_destroy (clip);
+
+        gsk_vulkan_render_add_render_pass (render, pass);
+        gsk_vulkan_render_pass_add (pass, render, node);
+        gsk_vulkan_render_add_cleanup_image (render, result);
+
+        /* assuming the unclipped bounds should go to texture coordinates 0..1,
+         * calculate the coordinates for the clipped texture size
+         */
+        tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
+        tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
+        tex_rect->size.width = bounds->size.width/clipped.size.width;
+        tex_rect->size.height = bounds->size.height/clipped.size.height;
+
+        return result;
+      }
+   }
+
+  GSK_NOTE (FALLBACK, g_print ("Node as texture not implemented for this case. Using %gx%g fallback surface\n",
+                               ceil (bounds->size.width),
+                               ceil (bounds->size.height)));
+#ifdef G_ENABLE_DEBUG
+  {
+    GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+    gsk_profiler_counter_add (profiler,
+                              self->fallback_pixels,
+                              ceil (bounds->size.width) * ceil (bounds->size.height));
+  }
+#endif
+
+  /* XXX: We could intersect bounds with clip bounds here */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                        ceil (bounds->size.width),
+                                        ceil (bounds->size.height));
+  cr = cairo_create (surface);
+  cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
+
+  gsk_render_node_draw (node, cr);
+
+  cairo_destroy (cr);
+
+got_surface:
+  result = gsk_vulkan_image_new_from_data (uploader,
+                                           cairo_image_surface_get_data (surface),
+                                           cairo_image_surface_get_width (surface),
+                                           cairo_image_surface_get_height (surface),
+                                           cairo_image_surface_get_stride (surface));
+
+  cairo_surface_destroy (surface);
+
+  gsk_vulkan_render_add_cleanup_image (render, result);
+
+  tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
+  tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
+  tex_rect->size.width = node->bounds.size.width/bounds->size.width;
+  tex_rect->size.height = node->bounds.size.height/bounds->size.height;
+
+  return result;
+}
+
+static void
+gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass  *self,
+                                        GskVulkanOpRender    *op,
+                                        GskVulkanRender      *render,
+                                        GskVulkanUploader    *uploader)
+{
+  GskRenderNode *node;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  node = op->node;
+
+  GSK_NOTE (FALLBACK,
+            g_print ("Upload op=%s, node %s[%p], bounds %gx%g\n",
+                     op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
+                     (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
+                     node->name ? node->name : node->node_class->type_name, node,
+                     ceil (node->bounds.size.width),
+                     ceil (node->bounds.size.height)));
+#ifdef G_ENABLE_DEBUG
+  {
+    GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+    gsk_profiler_counter_add (profiler,
+                              self->fallback_pixels,
+                              ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
+  }
+#endif
+
+  /* XXX: We could intersect bounds with clip bounds here */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                        ceil (node->bounds.size.width * self->scale_factor),
+                                        ceil (node->bounds.size.height * self->scale_factor));
+  cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
+  cr = cairo_create (surface);
+  cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
+
+  if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
+    {
+      cairo_rectangle (cr,
+                       op->clip.bounds.origin.x, op->clip.bounds.origin.y,
+                       op->clip.bounds.size.width, op->clip.bounds.size.height);
+      cairo_clip (cr);
+    }
+  else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
+    {
+      gsk_rounded_rect_path (&op->clip, cr);
+      cairo_clip (cr);
+    }
+  else
+    {
+      g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
+    }
+
+  gsk_render_node_draw (node, cr);
+
+  cairo_destroy (cr);
+
+  op->source = gsk_vulkan_image_new_from_data (uploader,
+                                               cairo_image_surface_get_data (surface),
+                                               cairo_image_surface_get_width (surface),
+                                               cairo_image_surface_get_height (surface),
+                                               cairo_image_surface_get_stride (surface));
+
+  op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+
+  cairo_surface_destroy (surface);
+
+  gsk_vulkan_render_add_cleanup_image (render, op->source);
+}
+
+void
+gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
+                               GskVulkanRender      *render,
+                               GskVulkanUploader    *uploader)
+{
+  GskVulkanOp *op;
+  guint i;
+  GskVulkanClip *clip = NULL;
+
+  for (i = 0; i < self->render_ops->len; i++)
+    {
+      op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_FALLBACK_CLIP:
+        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+          gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
+          break;
+
+        case GSK_VULKAN_OP_SURFACE:
+          {
+            cairo_surface_t *surface;
+
+            surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (op->render.node);
+            op->render.source = gsk_vulkan_image_new_from_data (uploader,
+                                                                cairo_image_surface_get_data (surface),
+                                                                cairo_image_surface_get_width (surface),
+                                                                cairo_image_surface_get_height (surface),
+                                                                cairo_image_surface_get_stride (surface));
+            op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+
+            gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+          }
+          break;
+
+        case GSK_VULKAN_OP_TEXT:
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          {
+            op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+                                                                   uploader,
+                                                                   op->text.texture_index);
+            gsk_vulkan_render_add_cleanup_image (render, op->text.source);
+          }
+          break;
+
+        case GSK_VULKAN_OP_TEXTURE:
+          {
+            op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+                                                                       gsk_texture_node_get_texture (op->render.node),
+                                                                       uploader);
+            op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+            gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+          }
+          break;
+
+        case GSK_VULKAN_OP_OPACITY:
+          {
+            GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            child,
+                                                                            &child->bounds,
+                                                                            clip,
+                                                                            &op->render.source_rect);
+          }
+          break;
+
+        case GSK_VULKAN_OP_REPEAT:
+          {
+            GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
+            const graphene_rect_t *bounds = &op->render.node->bounds;
+            const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (op->render.node);
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            child,
+                                                                            child_bounds,
+                                                                            NULL,
+                                                                            &op->render.source_rect);
+
+            op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
+            op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
+            op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
+            op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
+          }
+          break;
+
+        case GSK_VULKAN_OP_BLUR:
+          {
+            GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            child,
+                                                                            &child->bounds,
+                                                                            clip,
+                                                                            &op->render.source_rect);
+          }
+          break;
+
+        case GSK_VULKAN_OP_COLOR_MATRIX:
+          {
+            GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            child,
+                                                                            &child->bounds,
+                                                                            clip,
+                                                                            &op->render.source_rect);
+          }
+          break;
+
+        case GSK_VULKAN_OP_CROSS_FADE:
+          {
+            GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
+            GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
+            const graphene_rect_t *bounds = &op->render.node->bounds;
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            start,
+                                                                            &start->bounds,
+                                                                            clip,
+                                                                            &op->render.source_rect);
+            op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
+            op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
+            op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
+            op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
+
+            op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                             render,
+                                                                             uploader,
+                                                                             end,
+                                                                             &end->bounds,
+                                                                             clip,
+                                                                             &op->render.source2_rect);
+            op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
+            op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
+            op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
+            op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
+          }
+          break;
+
+        case GSK_VULKAN_OP_BLEND_MODE:
+          {
+            GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
+            GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
+            const graphene_rect_t *bounds = &op->render.node->bounds;
+
+            op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                            render,
+                                                                            uploader,
+                                                                            top,
+                                                                            &top->bounds,
+                                                                            clip,
+                                                                            &op->render.source_rect);
+            op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
+            op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
+            op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
+            op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
+
+            op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
+                                                                             render,
+                                                                             uploader,
+                                                                             bottom,
+                                                                             &bottom->bounds,
+                                                                             clip,
+                                                                             &op->render.source2_rect);
+            op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
+            op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
+            op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
+            op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
+          }
+          break;
+
+        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+          clip = &op->constants.constants.clip;
+          break;
+
+        default:
+          g_assert_not_reached ();
+        case GSK_VULKAN_OP_COLOR:
+        case GSK_VULKAN_OP_LINEAR_GRADIENT:
+        case GSK_VULKAN_OP_BORDER:
+        case GSK_VULKAN_OP_INSET_SHADOW:
+        case GSK_VULKAN_OP_OUTSET_SHADOW:
+          break;
+        }
+    }
+}
+
+static gsize
+gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
+{
+  GskVulkanOp *op;
+  gsize n_bytes;
+  guint i;
+
+  n_bytes = 0;
+  for (i = 0; i < self->render_ops->len; i++)
+    {
+      op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_FALLBACK_CLIP:
+        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+        case GSK_VULKAN_OP_SURFACE:
+        case GSK_VULKAN_OP_TEXTURE:
+        case GSK_VULKAN_OP_REPEAT:
+          op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_TEXT:
+          op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
+                                                                              op->text.num_glyphs);
+          n_bytes += op->text.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
+                                                                                    op->text.num_glyphs);
+          n_bytes += op->text.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_COLOR:
+          op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_LINEAR_GRADIENT:
+          op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_OPACITY:
+        case GSK_VULKAN_OP_COLOR_MATRIX:
+          op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_BLUR:
+          op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_BORDER:
+          op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_INSET_SHADOW:
+        case GSK_VULKAN_OP_OUTSET_SHADOW:
+          op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_CROSS_FADE:
+          op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        case GSK_VULKAN_OP_BLEND_MODE:
+          op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
+        default:
+          g_assert_not_reached ();
+
+        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+          continue;
+        }
+    }
+
+  return n_bytes;
+}
+
+static gsize
+gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
+                                            GskVulkanRender     *render,
+                                            guchar              *data,
+                                            gsize                offset,
+                                            gsize                total)
+{
+  GskVulkanOp *op;
+  gsize n_bytes;
+  guint i;
+
+  n_bytes = 0;
+  for (i = 0; i < self->render_ops->len; i++)
+    {
+      op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_FALLBACK_CLIP:
+        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+        case GSK_VULKAN_OP_SURFACE:
+        case GSK_VULKAN_OP_TEXTURE:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
+                                                             data + n_bytes + offset,
+                                                             &op->render.node->bounds,
+                                                             &op->render.source_rect);
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_REPEAT:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
+                                                             data + n_bytes + offset,
+                                                             &op->render.node->bounds,
+                                                             &op->render.source_rect);
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_TEXT:
+          {
+            op->text.vertex_offset = offset + n_bytes;
+            gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
+                                                          data + n_bytes + offset,
+                                                          GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+                                                          &op->text.node->bounds,
+                                                          (PangoFont *)gsk_text_node_peek_font (op->text.node),
+                                                          gsk_text_node_get_num_glyphs (op->text.node),
+                                                          gsk_text_node_peek_glyphs (op->text.node),
+                                                          gsk_text_node_peek_color (op->text.node),
+                                                          gsk_text_node_get_x (op->text.node),
+                                                          gsk_text_node_get_y (op->text.node),
+                                                          op->text.start_glyph,
+                                                          op->text.num_glyphs,
+                                                          op->text.scale);
+            n_bytes += op->text.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          {
+            op->text.vertex_offset = offset + n_bytes;
+            gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
+                                                                data + n_bytes + offset,
+                                                                GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+                                                                &op->text.node->bounds,
+                                                                (PangoFont *)gsk_text_node_peek_font (op->text.node),
+                                                                gsk_text_node_get_num_glyphs (op->text.node),
+                                                                gsk_text_node_peek_glyphs (op->text.node),
+                                                                gsk_text_node_get_x (op->text.node),
+                                                                gsk_text_node_get_y (op->text.node),
+                                                                op->text.start_glyph,
+                                                                op->text.num_glyphs,
+                                                                op->text.scale);
+            n_bytes += op->text.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_COLOR:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
+                                                           data + n_bytes + offset,
+                                                           &op->render.node->bounds,
+                                                           gsk_color_node_peek_color (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_LINEAR_GRADIENT:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
+                                                                     data + n_bytes + offset,
+                                                                     &op->render.node->bounds,
+                                                                     gsk_linear_gradient_node_peek_start (op->render.node),
+                                                                     gsk_linear_gradient_node_peek_end (op->render.node),
+                                                                     gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
+                                                                     gsk_linear_gradient_node_get_n_color_stops (op->render.node),
+                                                                     gsk_linear_gradient_node_peek_color_stops (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_OPACITY:
+          {
+            graphene_matrix_t color_matrix;
+            graphene_vec4_t color_offset;
+
+            graphene_matrix_init_from_float (&color_matrix,
+                                             (float[16]) {
+                                                 1.0, 0.0, 0.0, 0.0,
+                                                 0.0, 1.0, 0.0, 0.0,
+                                                 0.0, 0.0, 1.0, 0.0,
+                                                 0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
+                                             });
+            graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
+            op->render.vertex_offset = offset + n_bytes;
+
+            gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
+                                                            data + n_bytes + offset,
+                                                            &op->render.node->bounds,
+                                                            &op->render.source_rect,
+                                                            &color_matrix,
+                                                            &color_offset);
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_BLUR:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
+                                                          data + n_bytes + offset,
+                                                          &op->render.node->bounds,
+                                                          &op->render.source_rect,
+                                                          gsk_blur_node_get_radius (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_COLOR_MATRIX:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
+                                                            data + n_bytes + offset,
+                                                            &op->render.node->bounds,
+                                                            &op->render.source_rect,
+                                                            gsk_color_matrix_node_peek_color_matrix (op->render.node),
+                                                            gsk_color_matrix_node_peek_color_offset (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_BORDER:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
+                                                            data + n_bytes + offset,
+                                                            gsk_border_node_peek_outline (op->render.node),
+                                                            gsk_border_node_peek_widths (op->render.node),
+                                                            gsk_border_node_peek_colors (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_INSET_SHADOW:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
+                                                                data + n_bytes + offset,
+                                                                gsk_inset_shadow_node_peek_outline (op->render.node),
+                                                                gsk_inset_shadow_node_peek_color (op->render.node),
+                                                                gsk_inset_shadow_node_get_dx (op->render.node),
+                                                                gsk_inset_shadow_node_get_dy (op->render.node),
+                                                                gsk_inset_shadow_node_get_spread (op->render.node),
+                                                                gsk_inset_shadow_node_get_blur_radius (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_OUTSET_SHADOW:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
+                                                                data + n_bytes + offset,
+                                                                gsk_outset_shadow_node_peek_outline (op->render.node),
+                                                                gsk_outset_shadow_node_peek_color (op->render.node),
+                                                                gsk_outset_shadow_node_get_dx (op->render.node),
+                                                                gsk_outset_shadow_node_get_dy (op->render.node),
+                                                                gsk_outset_shadow_node_get_spread (op->render.node),
+                                                                gsk_outset_shadow_node_get_blur_radius (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_CROSS_FADE:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
+                                                                data + n_bytes + offset,
+                                                                &op->render.node->bounds,
+                                                                &op->render.source_rect,
+                                                                &op->render.source2_rect,
+                                                                gsk_cross_fade_node_get_progress (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        case GSK_VULKAN_OP_BLEND_MODE:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
+                                                                data + n_bytes + offset,
+                                                                &op->render.node->bounds,
+                                                                &op->render.source_rect,
+                                                                &op->render.source2_rect,
+                                                                gsk_blend_node_get_blend_mode (op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
+        default:
+          g_assert_not_reached ();
+        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+          continue;
+        }
+
+      g_assert (n_bytes + offset <= total);
+    }
+
+  return n_bytes;
+}
+
+static GskVulkanBuffer *
+gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
+                                        GskVulkanRender     *render)
+{
+  if (self->vertex_data == NULL)
+    {
+      gsize n_bytes;
+      guchar *data;
+
+      n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
+      self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
+      data = gsk_vulkan_buffer_map (self->vertex_data);
+      gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
+      gsk_vulkan_buffer_unmap (self->vertex_data);
+    }
+
+  return self->vertex_data;
+}
+
+gsize
+gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass  *self,
+                                            VkSemaphore         **semaphores)
+{
+  *semaphores = (VkSemaphore *)self->wait_semaphores->data;
+  return self->wait_semaphores->len;
+}
+
+gsize
+gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass  *self,
+                                              VkSemaphore         **semaphores)
+{
+  *semaphores = (VkSemaphore *)&self->signal_semaphore;
+  return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
+}
+
+void
+gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
+                                                GskVulkanRender     *render)
+{
+  GskVulkanOp *op;
+  guint i;
+
+  for (i = 0; i < self->render_ops->len; i++)
+    {
+      op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_FALLBACK_CLIP:
+        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+        case GSK_VULKAN_OP_SURFACE:
+        case GSK_VULKAN_OP_TEXTURE:
+        case GSK_VULKAN_OP_OPACITY:
+        case GSK_VULKAN_OP_BLUR:
+        case GSK_VULKAN_OP_COLOR_MATRIX:
+          if (op->render.source)
+            op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
+          break;
+
+        case GSK_VULKAN_OP_REPEAT:
+          if (op->render.source)
+            op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
+          break;
+
+        case GSK_VULKAN_OP_TEXT:
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
+          break;
+
+        case GSK_VULKAN_OP_CROSS_FADE:
+        case GSK_VULKAN_OP_BLEND_MODE:
+          if (op->render.source && op->render.source2)
+            {
+              op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
+              op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
+            }
+          break;
+
+        default:
+          g_assert_not_reached ();
+
+        case GSK_VULKAN_OP_COLOR:
+        case GSK_VULKAN_OP_LINEAR_GRADIENT:
+        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+        case GSK_VULKAN_OP_BORDER:
+        case GSK_VULKAN_OP_INSET_SHADOW:
+        case GSK_VULKAN_OP_OUTSET_SHADOW:
+          break;
+        }
+    }
+}
+
+static void
+gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass     *self,
+                                  GskVulkanRender         *render,
+                                  guint                    layout_count,
+                                  VkPipelineLayout        *pipeline_layout,
+                                  VkCommandBuffer          command_buffer)
+{
+  GskVulkanPipeline *current_pipeline = NULL;
+  gsize current_draw_index = 0;
+  GskVulkanOp *op;
+  guint i, step;
+  GskVulkanBuffer *vertex_buffer;
+
+  vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
+
+  for (i = 0; i < self->render_ops->len; i += step)
+    {
+      op = &g_array_index (self->render_ops, GskVulkanOp, i);
+      step = 1;
+
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_FALLBACK_CLIP:
+        case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+        case GSK_VULKAN_OP_SURFACE:
+        case GSK_VULKAN_OP_TEXTURE:
+        case GSK_VULKAN_OP_REPEAT:
+          if (!op->render.source)
+            continue;
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
+                                                                  command_buffer,
+                                                                  current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_TEXT:
+          if (current_pipeline != op->text.pipeline)
+            {
+              current_pipeline = op->text.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->text.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
+                                                               command_buffer,
+                                                               current_draw_index, op->text.num_glyphs);
+          break;
+
+        case GSK_VULKAN_OP_COLOR_TEXT:
+          if (current_pipeline != op->text.pipeline)
+            {
+              current_pipeline = op->text.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->text.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
+                                                                     command_buffer,
+                                                                     current_draw_index, op->text.num_glyphs);
+          break;
+
+        case GSK_VULKAN_OP_OPACITY:
+        case GSK_VULKAN_OP_COLOR_MATRIX:
+          if (!op->render.source)
+            continue;
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
+                                                                 command_buffer,
+                                                                 current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_BLUR:
+          if (!op->render.source)
+            continue;
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
+                                                               command_buffer,
+                                                               current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_COLOR:
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          for (step = 1; step + i < self->render_ops->len; step++)
+            {
+              GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
+              if (cmp->type != GSK_VULKAN_OP_COLOR || 
+                  cmp->render.pipeline != current_pipeline)
+                break;
+            }
+          current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
+                                                                command_buffer,
+                                                                current_draw_index, step);
+          break;
+
+        case GSK_VULKAN_OP_LINEAR_GRADIENT:
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+          current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
+                                                                          command_buffer,
+                                                                          current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_BORDER:
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+          current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
+                                                                 command_buffer,
+                                                                 current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_INSET_SHADOW:
+        case GSK_VULKAN_OP_OUTSET_SHADOW:
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+          current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
+                                                                     command_buffer,
+                                                                     current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+          for (int i = 0; i < layout_count; i++)
+            gsk_vulkan_push_constants_push (&op->constants.constants,
+                                            command_buffer,
+                                            pipeline_layout[i]);
+          break;
+
+        case GSK_VULKAN_OP_CROSS_FADE:
+          if (!op->render.source || !op->render.source2)
+            continue;
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   2,
+                                   (VkDescriptorSet[2]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
+                                                                     command_buffer,
+                                                                     current_draw_index, 1);
+          break;
+
+        case GSK_VULKAN_OP_BLEND_MODE:
+          if (!op->render.source || !op->render.source2)
+            continue;
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+                                   0,
+                                   2,
+                                   (VkDescriptorSet[2]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
+                                       gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
+                                   },
+                                   0,
+                                   NULL);
+
+          current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
+                                                                     command_buffer,
+                                                                     current_draw_index, 1);
+          break;
+
+        default:
+          g_assert_not_reached ();
+          break;
+        }
+    }
+}
+
+void
+gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
+                             GskVulkanRender         *render,
+                             guint                    layout_count,
+                             VkPipelineLayout        *pipeline_layout,
+                             VkCommandBuffer          command_buffer)
+{
+  guint i;
+
+  vkCmdSetViewport (command_buffer,
+                    0,
+                    1,
+                    &(VkViewport) {
+                        .x = 0,
+                        .y = 0,
+                        .width = self->viewport.size.width,
+                        .height = self->viewport.size.height,
+                        .minDepth = 0,
+                        .maxDepth = 1
+                    });
+
+  for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
+    {
+      cairo_rectangle_int_t rect;
+
+      cairo_region_get_rectangle (self->clip, i, &rect);
+
+      vkCmdSetScissor (command_buffer,
+                       0,
+                       1,
+                       &(VkRect2D) {
+                          { rect.x * self->scale_factor, rect.y * self->scale_factor },
+                          { rect.width * self->scale_factor, rect.height * self->scale_factor }
+                       });
+
+      vkCmdBeginRenderPass (command_buffer,
+                            &(VkRenderPassBeginInfo) {
+                                .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                .renderPass = self->render_pass,
+                                .framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
+                                .renderArea = { 
+                                    { rect.x * self->scale_factor, rect.y * self->scale_factor },
+                                    { rect.width * self->scale_factor, rect.height * self->scale_factor }
+                                },
+                                .clearValueCount = 1,
+                                .pClearValues = (VkClearValue [1]) {
+                                    { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
+                                }
+                            },
+                            VK_SUBPASS_CONTENTS_INLINE);
+
+      gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
+
+      vkCmdEndRenderPass (command_buffer);
+    }
+}
diff --git a/gsk/vulkan/gskvulkanrenderpassprivate.h b/gsk/vulkan/gskvulkanrenderpassprivate.h
new file mode 100644 (file)
index 0000000..379db3b
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
+#define __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gsk/gskrendernode.h>
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanrenderprivate.h"
+#include "gsk/gskprivate.h"
+
+G_BEGIN_DECLS
+
+
+GskVulkanRenderPass *   gsk_vulkan_render_pass_new                      (GdkVulkanContext       *context,
+                                                                         GskVulkanImage         *target,
+                                                                         int                     scale_factor,
+                                                                         graphene_matrix_t      *mv,
+                                                                         graphene_rect_t        *viewport,
+                                                                         cairo_region_t         *clip,
+                                                                         VkSemaphore             signal_semaphore);
+
+void                    gsk_vulkan_render_pass_free                     (GskVulkanRenderPass    *self);
+
+void                    gsk_vulkan_render_pass_add                      (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render,
+                                                                         GskRenderNode          *node);
+
+void                    gsk_vulkan_render_pass_upload                   (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render,
+                                                                         GskVulkanUploader      *uploader);
+void                    gsk_vulkan_render_pass_reserve_descriptor_sets  (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render);
+void                    gsk_vulkan_render_pass_draw                     (GskVulkanRenderPass    *self,
+                                                                         GskVulkanRender        *render,
+                                                                         guint                   layout_count,
+                                                                         VkPipelineLayout       *pipeline_layout,
+                                                                         VkCommandBuffer         command_buffer);
+gsize                   gsk_vulkan_render_pass_get_wait_semaphores      (GskVulkanRenderPass    *self,
+                                                                         VkSemaphore           **semaphores);
+gsize                   gsk_vulkan_render_pass_get_signal_semaphores    (GskVulkanRenderPass    *self,
+                                                                         VkSemaphore           **semaphores);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDER_PASS_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanrenderprivate.h b/gsk/vulkan/gskvulkanrenderprivate.h
new file mode 100644 (file)
index 0000000..45cfa38
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef __GSK_VULKAN_RENDER_PRIVATE_H__
+#define __GSK_VULKAN_RENDER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gsk/gskrendernode.h>
+
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderpassprivate.h"
+#include "gsk/gskprivate.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GSK_VULKAN_PIPELINE_TEXTURE,
+  GSK_VULKAN_PIPELINE_TEXTURE_CLIP,
+  GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_COLOR,
+  GSK_VULKAN_PIPELINE_COLOR_CLIP,
+  GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT,
+  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP,
+  GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_COLOR_MATRIX,
+  GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
+  GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_BORDER,
+  GSK_VULKAN_PIPELINE_BORDER_CLIP,
+  GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_INSET_SHADOW,
+  GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP,
+  GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_OUTSET_SHADOW,
+  GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP,
+  GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_BLUR,
+  GSK_VULKAN_PIPELINE_BLUR_CLIP,
+  GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_TEXT,
+  GSK_VULKAN_PIPELINE_TEXT_CLIP,
+  GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_COLOR_TEXT,
+  GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
+  GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_CROSS_FADE,
+  GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP,
+  GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED,
+  GSK_VULKAN_PIPELINE_BLEND_MODE,
+  GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP,
+  GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED,
+  /* add more */
+  GSK_VULKAN_N_PIPELINES
+} GskVulkanPipelineType;
+
+GskVulkanRender *       gsk_vulkan_render_new                           (GskRenderer            *renderer,
+                                                                         GdkVulkanContext       *context);
+void                    gsk_vulkan_render_free                          (GskVulkanRender        *self);
+
+gboolean                gsk_vulkan_render_is_busy                       (GskVulkanRender        *self);
+void                    gsk_vulkan_render_reset                         (GskVulkanRender        *self,
+                                                                         GskVulkanImage         *target,
+                                                                         const graphene_rect_t  *rect);
+
+GskRenderer *           gsk_vulkan_render_get_renderer                  (GskVulkanRender        *self);
+
+void                    gsk_vulkan_render_add_cleanup_image             (GskVulkanRender        *self,
+                                                                         GskVulkanImage         *image);
+
+void                    gsk_vulkan_render_add_node                      (GskVulkanRender        *self,
+                                                                         GskRenderNode          *node);
+
+void                    gsk_vulkan_render_add_render_pass               (GskVulkanRender        *self,
+                                                                         GskVulkanRenderPass    *pass);
+
+void                    gsk_vulkan_render_upload                        (GskVulkanRender        *self);
+
+GskVulkanPipeline *     gsk_vulkan_render_get_pipeline                  (GskVulkanRender        *self,
+                                                                         GskVulkanPipelineType   pipeline_type);
+VkDescriptorSet         gsk_vulkan_render_get_descriptor_set            (GskVulkanRender        *self,
+                                                                         gsize                   id);
+gsize                   gsk_vulkan_render_reserve_descriptor_set        (GskVulkanRender        *self,
+                                                                         GskVulkanImage         *source,
+                                                                         gboolean                repeat);
+void                    gsk_vulkan_render_draw                          (GskVulkanRender        *self);
+
+void                    gsk_vulkan_render_submit                        (GskVulkanRender        *self);
+
+GdkTexture *            gsk_vulkan_render_download_target               (GskVulkanRender        *self);
+VkFramebuffer           gsk_vulkan_render_get_framebuffer               (GskVulkanRender        *self,
+                                                                         GskVulkanImage         *image);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkanshader.c b/gsk/vulkan/gskvulkanshader.c
new file mode 100644 (file)
index 0000000..1010b21
--- /dev/null
@@ -0,0 +1,102 @@
+#include "config.h"
+
+#include "gskvulkanshaderprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanShader
+{
+  GdkVulkanContext *vulkan;
+
+  GskVulkanShaderType type;
+  VkShaderModule vk_shader;
+};
+
+static GskVulkanShader *
+gsk_vulkan_shader_new_from_bytes (GdkVulkanContext     *context,
+                                  GskVulkanShaderType   type,
+                                  GBytes               *bytes,
+                                  GError              **error)
+{
+  GskVulkanShader *self;
+  VkShaderModule shader;
+  VkResult res;
+
+  res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context),
+                                            &(VkShaderModuleCreateInfo) {
+                                                .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+                                                .codeSize = g_bytes_get_size (bytes),
+                                                .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
+                                            },
+                                            NULL,
+                                            &shader);
+  if (res != VK_SUCCESS)
+    {
+      /* Someone invent better error categories plz */
+      g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
+                   "Could not create shader: %s", gdk_vulkan_strerror (res));
+      return NULL;
+    }
+
+  self = g_slice_new0 (GskVulkanShader);
+
+  self->vulkan = g_object_ref (context);
+  self->type = type;
+  self->vk_shader = shader;
+
+  return self;
+}
+
+GskVulkanShader *
+gsk_vulkan_shader_new_from_resource (GdkVulkanContext     *context,
+                                     GskVulkanShaderType   type,
+                                     const char           *resource_name,
+                                     GError              **error)
+{
+  GskVulkanShader *self;
+  GBytes *bytes;
+  GError *local_error = NULL;
+  char *path;
+
+  path = g_strconcat ("/org/gtk/libgsk/vulkan/",
+                      resource_name, 
+                      type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv",
+                      NULL);
+  bytes = g_resources_lookup_data (path, 0, &local_error);
+  g_free (path);
+  if (bytes == NULL)
+    {
+      GSK_NOTE (VULKAN, g_printerr ("Error loading shader data: %s\n", local_error->message));
+      g_propagate_error (error, local_error);
+      return NULL;
+    }
+
+  self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error);
+  g_bytes_unref (bytes);
+
+  return self;
+}
+
+void
+gsk_vulkan_shader_free (GskVulkanShader *self)
+{
+  vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan),
+                         self->vk_shader,
+                         NULL);
+
+  g_object_unref (self->vulkan);
+
+  g_slice_free (GskVulkanShader, self);
+}
+
+GskVulkanShaderType
+gsk_vulkan_shader_get_type (GskVulkanShader *shader)
+{
+  return shader->type;
+}
+
+VkShaderModule
+gsk_vulkan_shader_get_module (GskVulkanShader *shader)
+{
+  return shader->vk_shader;
+}
+
diff --git a/gsk/vulkan/gskvulkanshaderprivate.h b/gsk/vulkan/gskvulkanshaderprivate.h
new file mode 100644 (file)
index 0000000..e94424f
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__
+#define __GSK_VULKAN_SHADER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GSK_VULKAN_SHADER_VERTEX,
+  GSK_VULKAN_SHADER_FRAGMENT
+} GskVulkanShaderType;
+
+typedef struct _GskVulkanShader GskVulkanShader;
+
+#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \
+  (VkPipelineShaderStageCreateInfo) { \
+  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
+  .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \
+  .module = gsk_vulkan_shader_get_module (shader), \
+  .pName = "main", \
+}
+
+GskVulkanShader *       gsk_vulkan_shader_new_from_resource             (GdkVulkanContext       *context,
+                                                                         GskVulkanShaderType     type,
+                                                                         const char             *resource_name,
+                                                                         GError                **error);
+void                    gsk_vulkan_shader_free                          (GskVulkanShader        *shader);
+
+GskVulkanShaderType     gsk_vulkan_shader_get_type                      (GskVulkanShader        *shader);
+VkShaderModule          gsk_vulkan_shader_get_module                    (GskVulkanShader        *shader);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_SHADER_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkantextpipeline.c b/gsk/vulkan/gskvulkantextpipeline.c
new file mode 100644 (file)
index 0000000..361c536
--- /dev/null
@@ -0,0 +1,170 @@
+#include "config.h"
+
+#include "gskvulkantextpipelineprivate.h"
+
+struct _GskVulkanTextPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
+
+struct _GskVulkanTextInstance
+{
+  float rect[4];
+  float tex_rect[4];
+  float color[4];
+};
+
+G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanTextInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
+      },
+      {
+          .location = 2,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_text_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanTextPipeline *self = GSK_VULKAN_TEXT_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_text_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_text_pipeline_class_init (GskVulkanTextPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_text_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_text_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_text_pipeline_init (GskVulkanTextPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_text_pipeline_new (GdkVulkanContext        *context,
+                              VkPipelineLayout         layout,
+                              const char              *shader_name,
+                              VkRenderPass             render_pass)
+{
+  return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, layout, shader_name, render_pass,
+                                       VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+gsize
+gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
+                                            int                    num_instances)
+{
+  return sizeof (GskVulkanTextInstance) * num_instances;
+}
+
+void
+gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline  *pipeline,
+                                              guchar                 *data,
+                                              GskVulkanRenderer      *renderer,
+                                              const graphene_rect_t  *rect,
+                                              PangoFont              *font,
+                                              guint                   total_glyphs,
+                                              const PangoGlyphInfo   *glyphs,
+                                              const GdkRGBA          *color,
+                                              float                   x,
+                                              float                   y,
+                                              guint                   start_glyph,
+                                              guint                   num_glyphs,
+                                              float                   scale)
+{
+  GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
+  int i;
+  int count = 0;
+  int x_position = 0;
+
+  for (i = 0; i < start_glyph; i++)
+    x_position += glyphs[i].geometry.width;
+
+  for (; i < total_glyphs && count < num_glyphs; i++)
+    {
+      const PangoGlyphInfo *gi = &glyphs[i];
+
+      if (gi->glyph != PANGO_GLYPH_EMPTY)
+        {
+          double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+          double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+          GskVulkanTextInstance *instance = &instances[count];
+          GskVulkanCachedGlyph *glyph;
+
+          glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+
+          instance->tex_rect[0] = glyph->tx;
+          instance->tex_rect[1] = glyph->ty;
+          instance->tex_rect[2] = glyph->tw;
+          instance->tex_rect[3] = glyph->th;
+
+          instance->rect[0] = x + cx + glyph->draw_x;
+          instance->rect[1] = y + cy + glyph->draw_y;
+          instance->rect[2] = glyph->draw_width;
+          instance->rect[3] = glyph->draw_height;
+
+          instance->color[0] = color->red;
+          instance->color[1] = color->green;
+          instance->color[2] = color->blue;
+          instance->color[3] = color->alpha;
+
+          count++;
+        }
+      x_position += gi->geometry.width;
+    }
+}
+
+gsize
+gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
+                               VkCommandBuffer        command_buffer,
+                               gsize                  offset,
+                               gsize                  n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkantextpipelineprivate.h b/gsk/vulkan/gskvulkantextpipelineprivate.h
new file mode 100644 (file)
index 0000000..47517de
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrendererprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanTextPipelineLayout GskVulkanTextPipelineLayout;
+
+#define GSK_TYPE_VULKAN_TEXT_PIPELINE (gsk_vulkan_text_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK, VULKAN_TEXT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_text_pipeline_new                   (GdkVulkanContext              *context,
+                                                                        VkPipelineLayout               layout,
+                                                                        const char                    *shader_name,
+                                                                        VkRenderPass                   render_pass);
+
+gsize                   gsk_vulkan_text_pipeline_count_vertex_data     (GskVulkanTextPipeline         *pipeline,
+                                                                        int                            num_instances);
+void                    gsk_vulkan_text_pipeline_collect_vertex_data   (GskVulkanTextPipeline         *pipeline,
+                                                                        guchar                         *data,
+                                                                        GskVulkanRenderer              *renderer,
+                                                                        const graphene_rect_t          *rect,
+                                                                        PangoFont                      *font,
+                                                                        guint                           total_glyphs,
+                                                                        const PangoGlyphInfo           *glyphs,
+                                                                        const GdkRGBA                  *color,
+                                                                        float                           x,
+                                                                        float                           y,
+                                                                        guint                           start_glyph,
+                                                                        guint                           num_glyphs,
+                                                                        float                           scale);
+gsize                   gsk_vulkan_text_pipeline_draw                  (GskVulkanTextPipeline         *pipeline,
+                                                                        VkCommandBuffer                 command_buffer,
+                                                                        gsize                           offset,
+                                                                        gsize                           n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/vulkan/gskvulkantexturepipeline.c b/gsk/vulkan/gskvulkantexturepipeline.c
new file mode 100644 (file)
index 0000000..9db7190
--- /dev/null
@@ -0,0 +1,122 @@
+#include "config.h"
+
+#include "gskvulkantexturepipelineprivate.h"
+
+struct _GskVulkanTexturePipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanTextureInstance GskVulkanTextureInstance;
+
+struct _GskVulkanTextureInstance
+{
+  float rect[4];
+  float tex_rect[4];
+};
+
+G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanTextureInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, rect),
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
+      }
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_texture_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanTexturePipeline *self = GSK_VULKAN_TEXTURE_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_texture_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_texture_pipeline_class_init (GskVulkanTexturePipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_texture_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_texture_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_texture_pipeline_init (GskVulkanTexturePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
+                                 VkPipelineLayout  layout,
+                                 const char       *shader_name,
+                                 VkRenderPass      render_pass)
+{
+  return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXTURE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline)
+{
+  return sizeof (GskVulkanTextureInstance);
+}
+
+void
+gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
+                                                 guchar                   *data,
+                                                 const graphene_rect_t    *rect,
+                                                 const graphene_rect_t    *tex_rect)
+{
+  GskVulkanTextureInstance *instance = (GskVulkanTextureInstance *) data;
+
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+  instance->tex_rect[0] = tex_rect->origin.x;
+  instance->tex_rect[1] = tex_rect->origin.y;
+  instance->tex_rect[2] = tex_rect->size.width;
+  instance->tex_rect[3] = tex_rect->size.height;
+}
+
+gsize
+gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
+                                  VkCommandBuffer           command_buffer,
+                                  gsize                     offset,
+                                  gsize                     n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/vulkan/gskvulkantexturepipelineprivate.h b/gsk/vulkan/gskvulkantexturepipelineprivate.h
new file mode 100644 (file)
index 0000000..c6435c4
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanTexturePipelineLayout GskVulkanTexturePipelineLayout;
+
+#define GSK_TYPE_VULKAN_TEXTURE_PIPELINE (gsk_vulkan_texture_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK, VULKAN_TEXTURE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_texture_pipeline_new                 (GdkVulkanContext         *context,
+                                                                         VkPipelineLayout          layout,
+                                                                         const char               *shader_name,
+                                                                         VkRenderPass              render_pass);
+
+gsize                   gsk_vulkan_texture_pipeline_count_vertex_data   (GskVulkanTexturePipeline *pipeline);
+void                    gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
+                                                                         guchar                   *data,
+                                                                         const graphene_rect_t    *rect,
+                                                                         const graphene_rect_t    *tex_rect);
+gsize                   gsk_vulkan_texture_pipeline_draw                (GskVulkanTexturePipeline *pipeline,
+                                                                         VkCommandBuffer           command_buffer,
+                                                                         gsize                     offset,
+                                                                         gsize                     n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__ */